コード例 #1
0
static int
client1(int argc, char **argv)
{
  /* client1 nodeID B -> msg state */
  curve25519_public_key_t B;
  uint8_t node_id[DIGEST_LEN];
  ntor_ntru_handshake_state_t *state = NULL;
  uint8_t msg[NTOR_NTRU_ONIONSKIN_LEN];

  char buf[4096];

  N_ARGS(4);
  BASE16(2, node_id, DIGEST_LEN);
  BASE16(3, B.public_key, CURVE25519_PUBKEY_LEN);

  if (onion_skin_ntor_ntru_create(node_id, &B, &state, msg)<0) {
    fprintf(stderr, "handshake failed");
    return 2;
  }

  base16_encode(buf, sizeof(buf), (const char*)msg, sizeof(msg));
  printf("%s\n", buf);
  base16_encode(buf, sizeof(buf), (void*)state, sizeof(*state));
  printf("%s\n", buf);

  ntor_ntru_handshake_state_free(state);
  return 0;
}
コード例 #2
0
ファイル: RouterStatus.cpp プロジェクト: Bodyfarm/vidalia
/** Constructor. Parses <b>status</b> for router status information. The given
 * string should match the router status entry format from Tor's dir-spec.txt.
 * The currently recognized lines are:
 *
 *  "r" SP nickname SP identity SP digest SP publication SP IP SP ORPort
 *      SP DirPort NL
 *  "s" SP Flags NL
 *
 * Unrecognized lines are currently ignored.
 *
 * */
RouterStatus::RouterStatus(const QStringList &status)
{
  bool ok;

  _valid = false;
  _flags = 0;

  _bandwidth = 0;

  foreach (QString line, status) {
    if (line.startsWith("r ")) {
      QStringList parts = line.split(" ", QString::SkipEmptyParts);
      if (parts.size() < 9)
        return;

      /* Nickname */
      _name = parts.at(1);
      /* Identity key digest */
      _id = base16_encode(QByteArray::fromBase64(parts.at(2).toAscii()));
      if (_id.isEmpty())
        return;
      /* Most recent descriptor digest */
      _digest = base16_encode(QByteArray::fromBase64(parts.at(3).toAscii()));
      if (_digest.isEmpty())
        return;
      /* Most recent publication date */
      _published = QDateTime::fromString(parts.at(4) + " " + parts.at(5),
                                         TIME_FORMAT);
      if (!_published.isValid())
        return;
      /* IP address */
      _ipAddress = QHostAddress(parts.at(6));
      if (_ipAddress.isNull())
        return;
      /* ORPort */
      _orPort = parts.at(7).toUInt(&ok);
      if (!ok)
        return;
      /* DirPort */
      _dirPort = parts.at(8).toUInt(&ok);
      if (!ok)
        return;

      _valid = true;
    } else if (line.startsWith("s ")) {
      /* Status flags */
      QStringList flags = line.split(" ", QString::SkipEmptyParts);
      flags.removeFirst(); /* Remove the "s" */

      foreach (QString flag, flags) {
        _flags |= flagValue(flag);
      }
    } else if (line.startsWith("w ")) {
コード例 #3
0
static int
client2(int argc, char **argv)
{
  struct ntor_ntru_handshake_state_t state;
  uint8_t msg[NTOR_NTRU_REPLY_LEN];
  int keybytes;
  uint8_t *keys;
  char *hexkeys;
  int result = 0;

  N_ARGS(5);
  BASE16(2, (&state), sizeof(state));
  BASE16(3, msg, sizeof(msg));
  INT(4, keybytes);

  keys = tor_malloc(keybytes);
  hexkeys = tor_malloc(keybytes*2+1);
  if (onion_skin_ntor_ntru_client_handshake(&state, msg, keys, keybytes)<0) {
    fprintf(stderr, "handshake failed");
    result = 2;
    goto done;
  }

  base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
  printf("%s\n", hexkeys);

 done:
  tor_free(keys);
  tor_free(hexkeys);
  return result;
}
コード例 #4
0
ファイル: m_user.c プロジェクト: KSoute/oftc-hybrid
/*
** mr_user
**      parv[0] = sender prefix
**      parv[1] = username (login name, account)
**      parv[2] = client host name (used only from other servers)
**      parv[3] = server host name (used only from other servers)
**      parv[4] = users real name info
*/
static void
mr_user(struct Client *client_p, struct Client *source_p,
        int parc, char *parv[])
{
  char *p;
  char *user;

  if (source_p->localClient->listener->flags & LISTENER_SERVER)
  {
    exit_client(source_p, &me, "Use a different port");
    return;
  }

  if ((p = strchr(parv[1], '@')) != NULL)
    *p = '\0'; 

  if (EmptyString(parv[4]))
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
               source_p->name[0] ? source_p->name : "*", "USER");
    return;
  }

  if(!EmptyString(source_p->name))
  {
    user = parv[1];
    if(*user == '&')
    {
      user++;
      if(EmptyString(user))
        user = parv[1];
      else
      {
        if(!EmptyString(source_p->certfp))
        {
          char buf[SHA_DIGEST_LENGTH*2+1];

          base16_encode(buf, sizeof(buf), source_p->certfp, sizeof(source_p->certfp));
          sendto_server(&me, NULL, NOCAPS, NOCAPS, ":%s AUTH 1 %s %s %s", me.name,
              user, source_p->name, buf);
        }
        else
        {
          sendto_server(&me, NULL, NOCAPS, NOCAPS, ":%s AUTH 0 %s %s %s", me.name,
              user, source_p->name, source_p->localClient->passwd);
        }
        
        strlcpy(source_p->info, parv[4], sizeof(source_p->info));

        return;
      }
    }
  }

  do_local_user(parv[0], client_p, source_p,
                parv[1], /* username */
                parv[2], /* host     */
                parv[3], /* server   */
                parv[4]	 /* users real name */ );
}
コード例 #5
0
ファイル: fuzz_strops.c プロジェクト: nmathewson/Tor
static chunk_t *
b16_enc(const chunk_t *inp)
{
  chunk_t *ch = chunk_new(inp->len * 2 + 1);
  base16_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len);
  return ch;
}
コード例 #6
0
ファイル: crypt.c プロジェクト: oftc/oftc-ircservices
char *
crypt_pass(char *password, int encode)
{
  EVP_MD_CTX *mdctx;
  const EVP_MD *md;
  unsigned char md_value[EVP_MAX_MD_SIZE];
  char buffer[2*DIGEST_LEN + 1];
  char *ret;
  unsigned int md_len;

  md = EVP_get_digestbyname(DIGEST_FUNCTION);

  mdctx = EVP_MD_CTX_create();
  EVP_MD_CTX_init(mdctx);
  EVP_DigestInit_ex(mdctx, md, NULL);
  EVP_DigestUpdate(mdctx, password, strlen(password));
  EVP_DigestFinal_ex(mdctx, md_value, &md_len);
  EVP_MD_CTX_destroy(mdctx);

  if(encode)
  {
    base16_encode(buffer, sizeof(buffer), (char *)md_value, DIGEST_LEN);
    DupString(ret, buffer);
  }
  else
  {
    ret = MyMalloc(DIGEST_LEN);
    memcpy(ret, md_value, DIGEST_LEN);
  }
  return ret;
}
コード例 #7
0
ファイル: test_ntor_cl.c プロジェクト: Archer-sys/tor
static int
server1(int argc, char **argv)
{
  uint8_t msg_in[NTOR_ONIONSKIN_LEN];
  curve25519_keypair_t kp;
  di_digest256_map_t *keymap=NULL;
  uint8_t node_id[DIGEST_LEN];
  int keybytes;

  uint8_t msg_out[NTOR_REPLY_LEN];
  uint8_t *keys = NULL;
  char *hexkeys = NULL;
  int result = 0;

  char buf[256];

  /* server1: b nodeID msg N -> msg keys */
  N_ARGS(6);
  BASE16(2, kp.seckey.secret_key, CURVE25519_SECKEY_LEN);
  BASE16(3, node_id, DIGEST_LEN);
  BASE16(4, msg_in, NTOR_ONIONSKIN_LEN);
  INT(5, keybytes);

  curve25519_public_key_generate(&kp.pubkey, &kp.seckey);
  dimap_add_entry(&keymap, kp.pubkey.public_key, &kp);

  keys = tor_malloc(keybytes);
  hexkeys = tor_malloc(keybytes*2+1);
  if (onion_skin_ntor_server_handshake(
                                msg_in, keymap, NULL, node_id, msg_out, keys,
                                (size_t)keybytes)<0) {
    fprintf(stderr, "handshake failed");
    result = 2;
    goto done;
  }

  base16_encode(buf, sizeof(buf), (const char*)msg_out, sizeof(msg_out));
  printf("%s\n", buf);
  base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
  printf("%s\n", hexkeys);

 done:
  tor_free(keys);
  tor_free(hexkeys);
  dimap_free(keymap, NULL);
  return result;
}
コード例 #8
0
ファイル: shadowtor.c プロジェクト: mikalv/shadow-plugin-tor
/* replacement for torflow in Tor. for now just grab the bandwidth we configured
 * in the XML and use that as the measured bandwidth value. since our configured
 * bandwidth doesnt change over time, this could just be run once (by setting the
 * time far in the future so the file is not seen as outdated). but we need to
 * run it after all routers are loaded, so its best to re-run periodically.
 *
 * eventually we will want an option to run something similar to the actual
 * torflow scripts that download files over Tor and computes bandwidth values.
 * in that case it needs to run more often to keep monitoring the actual state
 * of the network.
 *
 * torflow writes a few things to the v3bwfile. all Tor currently uses is:
 *
 * 0123456789
 * node_id=$0123456789ABCDEF0123456789ABCDEF01234567 bw=12345
 * ...
 *
 * where 0123456789 is the time, 0123456789ABCDEF0123456789ABCDEF01234567 is
 * the relay's fingerprint, and 12345 is the measured bandwidth in ?.
 */
void scalliontor_init_v3bw(ScallionTor* stor) {
	/* open the bw file, clearing it if it exists */
	FILE *v3bw = fopen(stor->v3bw_name, "w");
	if(v3bw == NULL) {
		stor->shadowlibFuncs->log(SHADOW_LOG_LEVEL_MESSAGE, __FUNCTION__,
				"v3bandwidth file not updated: can not open file '%s'\n", stor->v3bw_name);
		return;
	}

	time_t maxtime = -1;

	/* print time part on first line */
	if(fprintf(v3bw, "%lu\n", maxtime) < 0) {
		/* uhhhh... */
		stor->shadowlibFuncs->log(SHADOW_LOG_LEVEL_MESSAGE, __FUNCTION__,
		"v3bandwidth file not updated: can write time '%u' to file '%s'\n", maxtime, stor->v3bw_name);
		return;
	}

	routerlist_t *rlist = router_get_routerlist();
	routerinfo_t *rinfo;

	/* print an entry for each router */
	for (int i=0; i < smartlist_len(rlist->routers); i++) {
		rinfo = smartlist_get(rlist->routers, i);

		/* get the fingerprint from its digest */
		char node_id[HEX_DIGEST_LEN+1];
		base16_encode(node_id, HEX_DIGEST_LEN+1, rinfo->cache_info.identity_digest, DIGEST_LEN);

		/* the network address */
		in_addr_t netaddr = htonl(rinfo->addr);

		/* ask shadow for this node's configured bandwidth */
		guint bwdown = 0, bwup = 0;
		stor->shadowlibFuncs->getBandwidth(netaddr, &bwdown, &bwup);

		/* XXX careful here! shadow bandwidth may be different than the consensus
		 * right now i believe this v3bw file is not used to compute the consensus
		 * "w Bandwidth" line, and
		 * intercept_rep_hist_bandwidth_assess and
		 * intercept_router_get_advertised_bandwidth_capped
		 * takes care of things. so leave it for now.
		 */
		guint bw = MIN(bwup, bwdown);

		if(fprintf(v3bw, "node_id=$%s bw=%u\n", node_id, bw) < 0) {
			/* uhhhh... */
			stor->shadowlibFuncs->log(SHADOW_LOG_LEVEL_MESSAGE, __FUNCTION__,
					"v3bandwidth file not updated: can write line 'node_id=$%s bw=%u\n' to file '%s'\n", node_id, bw, stor->v3bw_name);
			return;
		}
	}

	fclose(v3bw);

	/* reschedule */
	stor->shadowlibFuncs->createCallback((ShadowPluginCallbackFunc)scalliontor_init_v3bw, (gpointer)stor, VTORFLOW_SCHED_PERIOD);
}
コード例 #9
0
/**
 * Finalise HTTP Digest
 *
 * @v ctx		Digest context
 * @v out		Buffer for digest output
 * @v len		Buffer length
 */
static void http_digest_final ( struct md5_context *ctx, char *out,
				size_t len ) {
	uint8_t digest[MD5_DIGEST_SIZE];

	/* Finalise and base16-encode MD5 digest */
	digest_final ( &md5_algorithm, ctx, digest );
	base16_encode ( digest, sizeof ( digest ), out, len );
}
コード例 #10
0
ファイル: rendmid.c プロジェクト: 80Z/Stealth
/** Process an ESTABLISH_RENDEZVOUS cell by setting the circuit's purpose and
 * rendezvous cookie.
 */
int
rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
                              size_t request_len)
{
  char hexid[9];
  int reason = END_CIRC_REASON_TORPROTOCOL;

  log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %u",
           (unsigned)circ->p_circ_id);

  if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) {
    log_warn(LD_PROTOCOL,
             "Tried to establish rendezvous on non-OR circuit with purpose %s",
             circuit_purpose_to_string(circ->base_.purpose));
    goto err;
  }

  if (circ->base_.n_chan) {
    log_warn(LD_PROTOCOL,
             "Tried to establish rendezvous on non-edge circuit");
    goto err;
  }

  if (request_len != REND_COOKIE_LEN) {
    log_fn(LOG_PROTOCOL_WARN,
           LD_PROTOCOL, "Invalid length on ESTABLISH_RENDEZVOUS.");
    goto err;
  }

  if (circuit_get_rendezvous(request)) {
    log_warn(LD_PROTOCOL,
             "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS.");
    goto err;
  }

  /* Acknowledge the request. */
  if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
                                   RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
                                   "", 0, NULL)<0) {
    log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
    reason = END_CIRC_REASON_INTERNAL;
    goto err;
  }

  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING);
  circuit_set_rendezvous_cookie(circ, request);

  base16_encode(hexid,9,(char*)request,4);

  log_info(LD_REND,
           "Established rendezvous point on circuit %u for cookie %s",
           (unsigned)circ->p_circ_id, hexid);

  return 0;
 err:
  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
  return -1;
}
コード例 #11
0
ファイル: s_bsd.c プロジェクト: Adam-/oftc-hybrid
/*
 * ssl_handshake - let OpenSSL initialize the protocol. Register for
 * read/write events if necessary.
 */
static void
ssl_handshake(int fd, struct Client *client_p)
{
  int ret = SSL_accept(client_p->localClient->fd.ssl);
  X509 *cert;

  if ((cert = SSL_get_peer_certificate(client_p->localClient->fd.ssl)) != NULL)
  {
    int res = SSL_get_verify_result(client_p->localClient->fd.ssl);
    if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
        res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
        res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
    {
      /* The client sent a certificate which verified OK */
      base16_encode(client_p->certfp, sizeof(client_p->certfp),
          (const char*)cert->sha1_hash, sizeof(cert->sha1_hash));
    }
    else
    {
      ilog(L_WARN, "Client %s!%s@%s gave bad SSL client certificate: %d",
          client_p->name, client_p->username, client_p->host, res);
    }

    X509_free(cert);
  }

  if (ret <= 0)
  {
    if((CurrentTime - client_p->firsttime) > 30)
    {
      exit_client(client_p, client_p, "Timeout during SSL handshake");
      return;
    }
    switch (SSL_get_error(client_p->localClient->fd.ssl, ret))
    {
      case SSL_ERROR_WANT_WRITE:
        comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
	               (PF *) ssl_handshake, client_p, 30);
        return;

      case SSL_ERROR_WANT_READ:
        comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
	               (PF *) ssl_handshake, client_p, 30);
        return;

      default:
        exit_client(client_p, client_p, "Error during SSL handshake");
        return;
    }
  }

  comm_settimeout(&client_p->localClient->fd, 0, NULL, NULL);
  execute_callback(auth_cb, client_p);
}
コード例 #12
0
ファイル: sgx-tor.c プロジェクト: johnjohnsp1/opensgx
/** Given a private or public key <b>pk</b>, put a hashed fingerprint of
 * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1
 * bytes of space).  Return 0 on success, -1 on failure.
 *
 * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest
 * of the ASN.1 encoding of the public key, converted to hexadecimal, in
 * upper case.
 */
int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
{
    char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN];
    if (crypto_pk_get_digest(pk, digest)) {
        return -1;
    }
    if (crypto_digest(hashed_digest, digest, DIGEST_LEN)) {
        return -1;
    }
    base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
    return 0;
}
コード例 #13
0
static smartlist_t *
cert_dl_status_sks_for_auth_id_mock(const char *digest)
{
  smartlist_t *list = NULL;
  char sk[DIGEST_LEN];
  char digest_str[HEX_DIGEST_LEN+1];
  char *tmp;
  int len;

  tt_assert(digest != NULL);
  base16_encode(digest_str, HEX_DIGEST_LEN + 1,
                digest, DIGEST_LEN);
  digest_str[HEX_DIGEST_LEN] = '\0';

  /*
   * Build a list of two hard-coded digests, depending on what we
   * were just passed.
   */
  if (strcmp(digest_str, auth_id_digest_1_str) == 0) {
    list = smartlist_new();
    len = base16_decode(sk, DIGEST_LEN,
                        auth_1_sk_1_str, strlen(auth_1_sk_1_str));
    tt_int_op(len, OP_EQ, DIGEST_LEN);
    tmp = tor_malloc(DIGEST_LEN);
    memcpy(tmp, sk, DIGEST_LEN);
    smartlist_add(list, tmp);
    len = base16_decode(sk, DIGEST_LEN,
                        auth_1_sk_2_str, strlen(auth_1_sk_2_str));
    tt_int_op(len, OP_EQ, DIGEST_LEN);
    tmp = tor_malloc(DIGEST_LEN);
    memcpy(tmp, sk, DIGEST_LEN);
    smartlist_add(list, tmp);
  } else if (strcmp(digest_str, auth_id_digest_2_str) == 0) {
    list = smartlist_new();
    len = base16_decode(sk, DIGEST_LEN,
                        auth_2_sk_1_str, strlen(auth_2_sk_1_str));
    tt_int_op(len, OP_EQ, DIGEST_LEN);
    tmp = tor_malloc(DIGEST_LEN);
    memcpy(tmp, sk, DIGEST_LEN);
    smartlist_add(list, tmp);
    len = base16_decode(sk, DIGEST_LEN,
                        auth_2_sk_2_str, strlen(auth_2_sk_2_str));
    tt_int_op(len, OP_EQ, DIGEST_LEN);
    tmp = tor_malloc(DIGEST_LEN);
    memcpy(tmp, sk, DIGEST_LEN);
    smartlist_add(list, tmp);
  }

 done:
  return list;
}
コード例 #14
0
ファイル: rendmid.c プロジェクト: pruby/Tor-Mirror
/** Process an ESTABLISH_RENDEZVOUS cell by setting the circuit's purpose and
 * rendezvous cookie.
 */
int
rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
                              size_t request_len)
{
  char hexid[9];
  int reason = END_CIRC_REASON_TORPROTOCOL;

  log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %d",
           circ->p_circ_id);

  if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
    log_warn(LD_PROTOCOL,
             "Tried to establish rendezvous on non-OR or non-edge circuit.");
    goto err;
  }

  if (request_len != REND_COOKIE_LEN) {
    log_warn(LD_PROTOCOL, "Invalid length on ESTABLISH_RENDEZVOUS.");
    goto err;
  }

  if (circuit_get_rendezvous(request)) {
    log_warn(LD_PROTOCOL,
             "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS.");
    goto err;
  }

  /* Acknowledge the request. */
  if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
                                   RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
                                   "", 0, NULL)<0) {
    log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
    reason = END_CIRC_REASON_INTERNAL;
    goto err;
  }

  circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  memcpy(circ->rend_token, request, REND_COOKIE_LEN);

  base16_encode(hexid,9,request,4);

  log_info(LD_REND,
           "Established rendezvous point on circuit %d for cookie %s",
           circ->p_circ_id, hexid);

  return 0;
 err:
  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
  return -1;
}
コード例 #15
0
ファイル: shared_random.c プロジェクト: Samdney/tor
/* Allocate a new commit object and initializing it with <b>rsa_identity</b>
 * that MUST be provided. The digest algorithm is set to the default one
 * that is supported. The rest is uninitialized. This never returns NULL. */
static sr_commit_t *
commit_new(const char *rsa_identity)
{
  sr_commit_t *commit;

  tor_assert(rsa_identity);

  commit = tor_malloc_zero(sizeof(*commit));
  commit->alg = SR_DIGEST_ALG;
  memcpy(commit->rsa_identity, rsa_identity, sizeof(commit->rsa_identity));
  base16_encode(commit->rsa_identity_hex, sizeof(commit->rsa_identity_hex),
                commit->rsa_identity, sizeof(commit->rsa_identity));
  return commit;
}
コード例 #16
0
static download_status_t *
cert_dl_status_fp_sk_mock(const char *fp_digest, const char *sk_digest)
{
  download_status_t *dl = NULL;
  char fp_digest_str[HEX_DIGEST_LEN+1], sk_digest_str[HEX_DIGEST_LEN+1];

  /*
   * Unpack the digests so we can compare them and figure out which
   * dl status we want.
   */

  tt_assert(fp_digest != NULL);
  base16_encode(fp_digest_str, HEX_DIGEST_LEN + 1,
                fp_digest, DIGEST_LEN);
  fp_digest_str[HEX_DIGEST_LEN] = '\0';
  tt_assert(sk_digest != NULL);
  base16_encode(sk_digest_str, HEX_DIGEST_LEN + 1,
                sk_digest, DIGEST_LEN);
  sk_digest_str[HEX_DIGEST_LEN] = '\0';

  if (strcmp(fp_digest_str, auth_id_digest_1_str) == 0) {
    if (strcmp(sk_digest_str, auth_1_sk_1_str) == 0) {
      dl = &auth_1_sk_1_dls;
    } else if (strcmp(sk_digest_str, auth_1_sk_2_str) == 0) {
      dl = &auth_1_sk_2_dls;
    }
  } else if (strcmp(fp_digest_str, auth_id_digest_2_str) == 0) {
    if (strcmp(sk_digest_str, auth_2_sk_1_str) == 0) {
      dl = &auth_2_sk_1_dls;
    } else if (strcmp(sk_digest_str, auth_2_sk_2_str) == 0) {
      dl = &auth_2_sk_2_dls;
    }
  }

 done:
  return dl;
}
コード例 #17
0
ファイル: sgx-tor.c プロジェクト: johnjohnsp1/opensgx
/** Given a private or public key <b>pk</b>, put a fingerprint of the
 * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of
 * space).  Return 0 on success, -1 on failure.
 *
 * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding
 * of the public key, converted to hexadecimal, in upper case, with a
 * space after every four digits.
 *
 * If <b>add_space</b> is false, omit the spaces.
 */
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
{
    char digest[DIGEST_LEN];
    char hexdigest[HEX_DIGEST_LEN+1];
    if (crypto_pk_get_digest(pk, digest)) {
        return -1;
    }
    base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN);
    if (add_space) {
        crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
    } else {
        sgx_strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1);
    }
    return 0;
}
コード例 #18
0
/**
 * Encrypts a string (str struct).
 *
 * @param src - the string that needs to be encrypted.Must NOT contain \0
 * @returns - the encrypted string, allocated in this function.
 */
str thig_encrypt(str src)
{
	int padding;
	str my_text={0,0},enc_text={0,0};
	cipherInstance ci2 = ci;
	str encoded={0,0};
	
	padding = (src.len%byteCnt)==0?0:byteCnt-(src.len%byteCnt);
	LOG(L_ERR,"DBG:"M_NAME":encrypt:String has length %d so needs padding %d\n",src.len,padding);

	my_text.len = src.len+padding;
	my_text.s = pkg_malloc(my_text.len);
	if (!my_text.s){
		LOG(L_ERR,"ERR:"M_NAME":encrypt: error allocating %d bytes\n",my_text.len);
		goto error;
	}	
	memcpy(my_text.s,src.s,src.len);
	memset(my_text.s+src.len,0,my_text.len-src.len);
	
	enc_text.s = pkg_malloc(my_text.len);
	if (!enc_text.s){
		LOG(L_ERR,"ERR:"M_NAME":encrypt: error allocating %d bytes\n",my_text.len);
		goto error;		
	}
	enc_text.len = my_text.len;

	printstr("String bef :",my_text);
	if (blockEncrypt(&ci2,&ki,(unsigned char*)my_text.s,my_text.len*8,(unsigned char*)enc_text.s) != my_text.len*8){
		LOG(L_ERR,"DBG:"M_NAME":encrypt: Error in encryption phase\n");
		goto error;
	}
	printstr("String aft :",enc_text);

#ifdef USE_BASE64
	encoded = base64_encode(enc_text);
#else
	encoded = base16_encode(enc_text);
#endif
	
	if (my_text.s) pkg_free(my_text.s);
	if (enc_text.s) pkg_free(enc_text.s);
	return encoded;	
error:
	if (my_text.s) pkg_free(my_text.s);
	if (enc_text.s) pkg_free(enc_text.s);
	enc_text.s = 0;enc_text.len=0;
	return enc_text;		
}
コード例 #19
0
ファイル: microdesc.c プロジェクト: jfrazelle/tor
/** Note that we failed to fetch a microdescriptor from the relay with
 *  <b>relay_digest</b> (of size DIGEST_LEN). */
void
microdesc_note_outdated_dirserver(const char *relay_digest)
{
  char relay_hexdigest[HEX_DIGEST_LEN+1];

  /* If we have a reasonably live consensus, then most of our dirservers should
   * still be caching all the microdescriptors in it. Reasonably live
   * consensuses are up to a day old (or a day in the future). But
   * microdescriptors expire 7 days after the last consensus that referenced
   * them. */
  if (!networkstatus_get_reasonably_live_consensus(approx_time(),
                                                   FLAV_MICRODESC)) {
    return;
  }

  if (!outdated_dirserver_list) {
    outdated_dirserver_list = smartlist_new();
  }

  tor_assert(outdated_dirserver_list);

  /* If the list grows too big, clean it up */
  if (BUG(smartlist_len(outdated_dirserver_list) >
          TOO_MANY_OUTDATED_DIRSERVERS)) {
    microdesc_reset_outdated_dirservers_list();
  }

  /* Turn the binary relay digest to a hex since smartlists have better support
   * for strings than digests. */
  base16_encode(relay_hexdigest,sizeof(relay_hexdigest),
                relay_digest, DIGEST_LEN);

  /* Make sure we don't add a dirauth as an outdated dirserver */
  if (router_get_trusteddirserver_by_digest(relay_digest)) {
    log_info(LD_GENERAL, "Auth %s gave us outdated dirinfo.", relay_hexdigest);
    return;
  }

  /* Don't double-add outdated dirservers */
  if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
    return;
  }

  /* Add it to the list of outdated dirservers */
  smartlist_add_strdup(outdated_dirserver_list, relay_hexdigest);

  log_info(LD_GENERAL, "Noted %s as outdated md dirserver", relay_hexdigest);
}
コード例 #20
0
ファイル: pubkey.c プロジェクト: JosephSWilliams/cryptotun
int main(int argc, char **argv) {
 if (argc>1) {
  unsigned char pk[64];
  unsigned char sk[32];
  int n;
  if (((n=open(argv[1],0))<0)||(read(n,sk,32)<32)||(close(n)<0)) return 64;
  crypto_scalarmult_curve25519_base(pk,sk);
  memcpy(sk,pk,32);
  if (base16_encode(pk,sk,32)!=64) return 255;
  if (write(1,"pubkey: ",8)!=8) return 255;
  if (write(1,pk,64)!=64) return 255;
  if (write(1,"\n",1)-1) return 255;
  return 0;
 }
 write(2,USAGE,strlen(USAGE));
 return 64;
}
コード例 #21
0
ファイル: basex.c プロジェクト: GrayTShirt/libvigor
/**
  Encode data into a NULL-terminated hex string.

  A convenience wrapper around @base16_encode, this function will return
  a NULL-terminated string containing the hexadecimal (base-16) representation
  of the input buffer $src, which should be $len bytes long.

  On success, returns a pointer to the newly-allocated string.  The caller is
  responsible from memory management from then on.

  On failure, returns NULL and sets errno appropriately:

    - **`EINVAL`** - $len is too small (0 or below).
 */
char* base16_encodestr(const void *src, size_t len)
{
	assert(src);
	errno = EINVAL;
	if (len <= 0) return NULL;

	size_t dlen = len * 2;
	char *dst = vmalloc(sizeof(char) * (dlen + 1));

	int rc = base16_encode(dst, dlen, src, len);
	if (rc < 0) {
		free(dst);
		return NULL;
	}

	dst[rc] = '\0';
	return dst;
}
コード例 #22
0
ファイル: certmgmt.c プロジェクト: andrewrothstein/ipxe
/**
 * Display status of a certificate
 *
 * @v cert		X.509 certificate
 */
void certstat ( struct x509_certificate *cert ) {
	struct digest_algorithm *digest = &sha1_algorithm;
	uint8_t fingerprint[ digest->digestsize ];
	char buf[ base16_encoded_len ( sizeof ( fingerprint ) ) + 1 /* NUL */ ];

	/* Generate fingerprint */
	x509_fingerprint ( cert, digest, fingerprint );
	base16_encode ( fingerprint, sizeof ( fingerprint ),
			buf, sizeof ( buf ) );

	/* Print certificate status */
	printf ( "%s : %s", x509_name ( cert ), buf );
	if ( cert->flags & X509_FL_PERMANENT )
		printf ( " [PERMANENT]" );
	if ( cert->flags & X509_FL_EXPLICIT )
		printf ( " [EXPLICIT]" );
	if ( x509_is_valid ( cert ) )
		printf ( " [VALIDATED]" );
	printf ( "\n" );
}
コード例 #23
0
static download_status_t *
cert_dl_status_def_for_auth_mock(const char *digest)
{
  download_status_t *dl = NULL;
  char digest_str[HEX_DIGEST_LEN+1];

  tt_assert(digest != NULL);
  base16_encode(digest_str, HEX_DIGEST_LEN + 1,
                digest, DIGEST_LEN);
  digest_str[HEX_DIGEST_LEN] = '\0';

  if (strcmp(digest_str, auth_id_digest_1_str) == 0) {
    dl = &auth_def_cert_download_status_1;
  } else if (strcmp(digest_str, auth_id_digest_2_str) == 0) {
    dl = &auth_def_cert_download_status_2;
  }

 done:
  return dl;
}
コード例 #24
0
ファイル: microdesc.c プロジェクト: jfrazelle/tor
/** Return True if the relay with <b>relay_digest</b> (size DIGEST_LEN) is an
 *  outdated dirserver */
int
microdesc_relay_is_outdated_dirserver(const char *relay_digest)
{
  char relay_hexdigest[HEX_DIGEST_LEN+1];

  if (!outdated_dirserver_list) {
    return 0;
  }

  /* Convert identity digest to hex digest */
  base16_encode(relay_hexdigest, sizeof(relay_hexdigest),
                relay_digest, DIGEST_LEN);

  /* Last time we tried to fetch microdescs, was this directory mirror missing
   * any mds we asked for? */
  if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
    return 1;
  }

  return 0;
}
コード例 #25
0
static download_status_t *
descbr_get_dl_by_digest_mock(const char *digest)
{
  download_status_t *dl = NULL;
  char digest_str[HEX_DIGEST_LEN+1];

  if (!disable_descbr) {
    tt_assert(digest != NULL);
    base16_encode(digest_str, HEX_DIGEST_LEN + 1,
                  digest, DIGEST_LEN);
    digest_str[HEX_DIGEST_LEN] = '\0';

    if (strcmp(digest_str, descbr_digest_1_str) == 0) {
      dl = &descbr_digest_1_dl;
    } else if (strcmp(digest_str, descbr_digest_2_str) == 0) {
      dl = &descbr_digest_2_dl;
    }
  }

 done:
  return dl;
}
コード例 #26
0
ファイル: sdp-mpeg4.c プロジェクト: ireader/media-server
int sdp_mpeg4_es(uint8_t *data, int bytes, int payload, int frequence, const void* extra, int extra_size)
{
	static const char* pattern =
		"m=video 0 RTP/AVP %d\n"
		"a=rtpmap:%d MP4V-ES/90000\n"
		"a=fmtp:%d profile-level-id=1;config=";

	int r, n;
	uint8_t i;

	n = snprintf((char*)data, bytes, pattern, payload, payload, payload);

	if (n + extra_size * 2 + 1 > bytes)
		return -1; // // don't have enough memory

	// It is a hexadecimal representation of an octet string that 
	// expresses the MPEG-4 Visual configuration information
	n += base16_encode(data + n, extra, extra_size);

	if (n < bytes)
		data[n++] = '\n';
	return n;
}
コード例 #27
0
ファイル: rendmid.c プロジェクト: 80Z/Stealth
/** Process a RENDEZVOUS1 cell by looking up the correct rendezvous
 * circuit by its relaying the cell's body in a RENDEZVOUS2 cell, and
 * connecting the two circuits.
 */
int
rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
                    size_t request_len)
{
  or_circuit_t *rend_circ;
  char hexid[9];
  int reason = END_CIRC_REASON_INTERNAL;

  if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
    log_info(LD_REND,
             "Tried to complete rendezvous on non-OR or non-edge circuit %u.",
             (unsigned)circ->p_circ_id);
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }

  if (request_len != REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
         "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.",
         (int)request_len, (unsigned)circ->p_circ_id);
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }

  base16_encode(hexid, sizeof(hexid), (const char*)request, 4);

  log_info(LD_REND,
           "Got request for rendezvous from circuit %u to cookie %s.",
           (unsigned)circ->p_circ_id, hexid);

  rend_circ = circuit_get_rendezvous(request);
  if (!rend_circ) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
         "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.",
         hexid);
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }

  /* Send the RENDEZVOUS2 cell to Alice. */
  if (relay_send_command_from_edge(0, TO_CIRCUIT(rend_circ),
                                   RELAY_COMMAND_RENDEZVOUS2,
                                   (char*)(request+REND_COOKIE_LEN),
                                   request_len-REND_COOKIE_LEN, NULL)) {
    log_warn(LD_GENERAL,
             "Unable to send RENDEZVOUS2 cell to client on circuit %u.",
             (unsigned)rend_circ->p_circ_id);
    goto err;
  }

  /* Join the circuits. */
  log_info(LD_REND,
           "Completing rendezvous: circuit %u joins circuit %u (cookie %s)",
           (unsigned)circ->p_circ_id, (unsigned)rend_circ->p_circ_id, hexid);

  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED);
  circuit_change_purpose(TO_CIRCUIT(rend_circ),
                         CIRCUIT_PURPOSE_REND_ESTABLISHED);
  circuit_set_rendezvous_cookie(circ, NULL);

  rend_circ->rend_splice = circ;
  circ->rend_splice = rend_circ;

  return 0;
 err:
  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
  return -1;
}
コード例 #28
0
ファイル: control_auth.c プロジェクト: nmathewson/Tor
/** Called when we get an AUTHCHALLENGE command. */
int
handle_control_authchallenge(control_connection_t *conn, uint32_t len,
                             const char *body)
{
  const char *cp = body;
  char *client_nonce;
  size_t client_nonce_len;
  char server_hash[DIGEST256_LEN];
  char server_hash_encoded[HEX_DIGEST256_LEN+1];
  char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN];
  char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1];

  cp += strspn(cp, " \t\n\r");
  if (!strcasecmpstart(cp, "SAFECOOKIE")) {
    cp += strlen("SAFECOOKIE");
  } else {
    connection_write_str_to_buf("513 AUTHCHALLENGE only supports SAFECOOKIE "
                                "authentication\r\n", conn);
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  if (!authentication_cookie_is_set) {
    connection_write_str_to_buf("515 Cookie authentication is disabled\r\n",
                                conn);
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  cp += strspn(cp, " \t\n\r");
  if (*cp == '"') {
    const char *newcp =
      decode_escaped_string(cp, len - (cp - body),
                            &client_nonce, &client_nonce_len);
    if (newcp == NULL) {
      connection_write_str_to_buf("513 Invalid quoted client nonce\r\n",
                                  conn);
      connection_mark_for_close(TO_CONN(conn));
      return -1;
    }
    cp = newcp;
  } else {
    size_t client_nonce_encoded_len = strspn(cp, "0123456789ABCDEFabcdef");

    client_nonce_len = client_nonce_encoded_len / 2;
    client_nonce = tor_malloc_zero(client_nonce_len);

    if (base16_decode(client_nonce, client_nonce_len,
                      cp, client_nonce_encoded_len)
                      != (int) client_nonce_len) {
      connection_write_str_to_buf("513 Invalid base16 client nonce\r\n",
                                  conn);
      connection_mark_for_close(TO_CONN(conn));
      tor_free(client_nonce);
      return -1;
    }

    cp += client_nonce_encoded_len;
  }

  cp += strspn(cp, " \t\n\r");
  if (*cp != '\0' ||
      cp != body + len) {
    connection_write_str_to_buf("513 Junk at end of AUTHCHALLENGE command\r\n",
                                conn);
    connection_mark_for_close(TO_CONN(conn));
    tor_free(client_nonce);
    return -1;
  }
  crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);

  /* Now compute and send the server-to-controller response, and the
   * server's nonce. */
  tor_assert(authentication_cookie != NULL);

  {
    size_t tmp_len = (AUTHENTICATION_COOKIE_LEN +
                      client_nonce_len +
                      SAFECOOKIE_SERVER_NONCE_LEN);
    char *tmp = tor_malloc_zero(tmp_len);
    char *client_hash = tor_malloc_zero(DIGEST256_LEN);
    memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN);
    memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len);
    memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len,
           server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);

    crypto_hmac_sha256(server_hash,
                       SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT,
                       strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT),
                       tmp,
                       tmp_len);

    crypto_hmac_sha256(client_hash,
                       SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT,
                       strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT),
                       tmp,
                       tmp_len);

    conn->safecookie_client_hash = client_hash;

    tor_free(tmp);
  }

  base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
                server_hash, sizeof(server_hash));
  base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
                server_nonce, sizeof(server_nonce));

  connection_printf_to_buf(conn,
                           "250 AUTHCHALLENGE SERVERHASH=%s "
                           "SERVERNONCE=%s\r\n",
                           server_hash_encoded,
                           server_nonce_encoded);

  tor_free(client_nonce);
  return 0;
}
コード例 #29
0
ファイル: test_crypto.c プロジェクト: Lab414/30May
/** Run unit tests for misc crypto formatting functionality (base64, base32,
 * fingerprints, etc) */
static void
test_crypto_formats(void)
{
  char *data1 = NULL, *data2 = NULL, *data3 = NULL;
  int i, j, idx;

  data1 = tor_malloc(1024);
  data2 = tor_malloc(1024);
  data3 = tor_malloc(1024);
  test_assert(data1 && data2 && data3);

  /* Base64 tests */
  memset(data1, 6, 1024);
  for (idx = 0; idx < 10; ++idx) {
    i = base64_encode(data2, 1024, data1, idx);
    test_assert(i >= 0);
    j = base64_decode(data3, 1024, data2, i);
    test_eq(j,idx);
    test_memeq(data3, data1, idx);
  }

  strlcpy(data1, "Test string that contains 35 chars.", 1024);
  strlcat(data1, " 2nd string that contains 35 chars.", 1024);

  i = base64_encode(data2, 1024, data1, 71);
  test_assert(i >= 0);
  j = base64_decode(data3, 1024, data2, i);
  test_eq(j, 71);
  test_streq(data3, data1);
  test_assert(data2[i] == '\0');

  crypto_rand(data1, DIGEST_LEN);
  memset(data2, 100, 1024);
  digest_to_base64(data2, data1);
  test_eq(BASE64_DIGEST_LEN, strlen(data2));
  test_eq(100, data2[BASE64_DIGEST_LEN+2]);
  memset(data3, 99, 1024);
  test_eq(digest_from_base64(data3, data2), 0);
  test_memeq(data1, data3, DIGEST_LEN);
  test_eq(99, data3[DIGEST_LEN+1]);

  test_assert(digest_from_base64(data3, "###") < 0);

  /* Encoding SHA256 */
  crypto_rand(data2, DIGEST256_LEN);
  memset(data2, 100, 1024);
  digest256_to_base64(data2, data1);
  test_eq(BASE64_DIGEST256_LEN, strlen(data2));
  test_eq(100, data2[BASE64_DIGEST256_LEN+2]);
  memset(data3, 99, 1024);
  test_eq(digest256_from_base64(data3, data2), 0);
  test_memeq(data1, data3, DIGEST256_LEN);
  test_eq(99, data3[DIGEST256_LEN+1]);

  /* Base32 tests */
  strlcpy(data1, "5chrs", 1024);
  /* bit pattern is:  [35 63 68 72 73] ->
   *        [00110101 01100011 01101000 01110010 01110011]
   * By 5s: [00110 10101 10001 10110 10000 11100 10011 10011]
   */
  base32_encode(data2, 9, data1, 5);
  test_streq(data2, "gvrwq4tt");

  strlcpy(data1, "\xFF\xF5\x6D\x44\xAE\x0D\x5C\xC9\x62\xC4", 1024);
  base32_encode(data2, 30, data1, 10);
  test_streq(data2, "772w2rfobvomsywe");

  /* Base16 tests */
  strlcpy(data1, "6chrs\xff", 1024);
  base16_encode(data2, 13, data1, 6);
  test_streq(data2, "3663687273FF");

  strlcpy(data1, "f0d678affc000100", 1024);
  i = base16_decode(data2, 8, data1, 16);
  test_eq(i,0);
  test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8);

  /* now try some failing base16 decodes */
  test_eq(-1, base16_decode(data2, 8, data1, 15)); /* odd input len */
  test_eq(-1, base16_decode(data2, 7, data1, 16)); /* dest too short */
  strlcpy(data1, "f0dz!8affc000100", 1024);
  test_eq(-1, base16_decode(data2, 8, data1, 16));

  tor_free(data1);
  tor_free(data2);
  tor_free(data3);

  /* Add spaces to fingerprint */
  {
    data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000");
    test_eq(strlen(data1), 40);
    data2 = tor_malloc(FINGERPRINT_LEN+1);
    add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1);
    test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000");
    tor_free(data1);
    tor_free(data2);
  }

 done:
  tor_free(data1);
  tor_free(data2);
  tor_free(data3);
}
コード例 #30
0
ファイル: fmt_routerstatus.c プロジェクト: nmathewson/Tor
/** Helper: write the router-status information in <b>rs</b> into a newly
 * allocated character buffer.  Use the same format as in network-status
 * documents.  If <b>version</b> is non-NULL, add a "v" line for the platform.
 *
 * consensus_method is the current consensus method when format is
 * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
 * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
 *
 * Return 0 on success, -1 on failure.
 *
 * The format argument has one of the following values:
 *   NS_V2 - Output an entry suitable for a V2 NS opinion document
 *   NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
 *        for consensus_method.
 *   NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
 *        consensus entry for consensus_method.
 *   NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
 *        it contains additional information for the vote.
 *   NS_CONTROL_PORT - Output a NS document for the control port.
 */
char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
                          const char *protocols,
                          routerstatus_format_type_t format,
                          int consensus_method,
                          const vote_routerstatus_t *vrs)
{
  char *summary;
  char *result = NULL;

  char published[ISO_TIME_LEN+1];
  char identity64[BASE64_DIGEST_LEN+1];
  char digest64[BASE64_DIGEST_LEN+1];
  smartlist_t *chunks = smartlist_new();

  format_iso_time(published, rs->published_on);
  digest_to_base64(identity64, rs->identity_digest);
  digest_to_base64(digest64, rs->descriptor_digest);

  smartlist_add_asprintf(chunks,
                   "r %s %s %s%s%s %s %d %d\n",
                   rs->nickname,
                   identity64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
                   published,
                   fmt_addr32(rs->addr),
                   (int)rs->or_port,
                   (int)rs->dir_port);

  /* TODO: Maybe we want to pass in what we need to build the rest of
   * this here, instead of in the caller. Then we could use the
   * networkstatus_type_t values, with an additional control port value
   * added -MP */

  /* V3 microdesc consensuses only have "a" lines in later consensus methods
   */
  if (format == NS_V3_CONSENSUS_MICRODESC &&
      consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
    goto done;

  /* Possible "a" line. At most one for now. */
  if (!tor_addr_is_null(&rs->ipv6_addr)) {
    smartlist_add_asprintf(chunks, "a %s\n",
                           fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
  }

  if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
    goto done;

  smartlist_add_asprintf(chunks,
                   "s%s%s%s%s%s%s%s%s%s%s%s\n",
                  /* These must stay in alphabetical order. */
                   rs->is_authority?" Authority":"",
                   rs->is_bad_exit?" BadExit":"",
                   rs->is_exit?" Exit":"",
                   rs->is_fast?" Fast":"",
                   rs->is_possible_guard?" Guard":"",
                   rs->is_hs_dir?" HSDir":"",
                   rs->is_flagged_running?" Running":"",
                   rs->is_stable?" Stable":"",
                   rs->is_staledesc?" StaleDesc":"",
                   rs->is_v2_dir?" V2Dir":"",
                   rs->is_valid?" Valid":"");

  /* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
  if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
    smartlist_add_asprintf(chunks, "v %s\n", version);
  }
  if (protocols) {
    smartlist_add_asprintf(chunks, "pr %s\n", protocols);
  }

  if (format != NS_V2) {
    const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
    uint32_t bw_kb;

    if (format != NS_CONTROL_PORT) {
      /* Blow up more or less nicely if we didn't get anything or not the
       * thing we expected.
       */
      if (!desc) {
        char id[HEX_DIGEST_LEN+1];
        char dd[HEX_DIGEST_LEN+1];

        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
        log_warn(LD_BUG, "Cannot get any descriptor for %s "
            "(wanted descriptor %s).",
            id, dd);
        goto err;
      }

      /* This assert could fire for the control port, because
       * it can request NS documents before all descriptors
       * have been fetched. Therefore, we only do this test when
       * format != NS_CONTROL_PORT. */
      if (tor_memneq(desc->cache_info.signed_descriptor_digest,
            rs->descriptor_digest,
            DIGEST_LEN)) {
        char rl_d[HEX_DIGEST_LEN+1];
        char rs_d[HEX_DIGEST_LEN+1];
        char id[HEX_DIGEST_LEN+1];

        base16_encode(rl_d, sizeof(rl_d),
            desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
        base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        log_err(LD_BUG, "descriptor digest in routerlist does not match "
            "the one in routerstatus: %s vs %s "
            "(router %s)\n",
            rl_d, rs_d, id);

        tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
              rs->descriptor_digest,
              DIGEST_LEN));
      }
    }

    if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
      bw_kb = rs->bandwidth_kb;
    } else {
      tor_assert(desc);
      bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
    }
    smartlist_add_asprintf(chunks,
                     "w Bandwidth=%d", bw_kb);

    if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
      smartlist_add_asprintf(chunks,
                       " Measured=%d", vrs->measured_bw_kb);
    }
    /* Write down guardfraction information if we have it. */
    if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
      smartlist_add_asprintf(chunks,
                             " GuardFraction=%d",
                             vrs->status.guardfraction_percentage);
    }

    smartlist_add_strdup(chunks, "\n");

    if (desc) {
      summary = policy_summarize(desc->exit_policy, AF_INET);
      smartlist_add_asprintf(chunks, "p %s\n", summary);
      tor_free(summary);
    }

    if (format == NS_V3_VOTE && vrs) {
      if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
        smartlist_add_strdup(chunks, "id ed25519 none\n");
      } else {
        char ed_b64[BASE64_DIGEST256_LEN+1];
        digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
        smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
      }
    }
  }

 done:
  result = smartlist_join_strings(chunks, "", 0, NULL);

 err:
  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
  smartlist_free(chunks);

  return result;
}