示例#1
0
/**
 * Parse the metaserver certificate information.
 *
 * @param server
 * Metaserver entry.
 * @return
 * True on success, false on failure.
 */
static bool
parse_metaserver_cert (server_struct *server)
{
    HARD_ASSERT(server != NULL);

    if (server->cert == NULL || server->cert_sig == NULL) {
        /* No certificate. */
        return true;
    }

    /* Generate a SHA512 hash of the certificate's contents. */
    unsigned char cert_digest[SHA512_DIGEST_LENGTH];
    if (SHA512((unsigned char *) server->cert,
               strlen(server->cert),
               cert_digest) == NULL) {
        LOG(ERROR, "SHA512() failed: %s",
            ERR_error_string(ERR_get_error(), NULL));
        return false;
    }

    char cert_hash[SHA512_DIGEST_LENGTH * 2 + 1];
    SOFT_ASSERT_RC(string_tohex(VS(cert_digest),
                                VS(cert_hash),
                                false) == sizeof(cert_hash) - 1,
                   false,
                   "string_tohex failed");
    string_tolower(cert_hash);

    /* Verify the signature. */
    if (!curl_verify(CURL_PKEY_TRUST_ULTIMATE,
                     cert_hash,
                     strlen(cert_hash),
                     server->cert_sig,
                     server->cert_sig_len)) {
        LOG(ERROR, "Failed to verify signature");
        return false;
    }

    server_cert_info_t *info = ecalloc(1, sizeof(*info));

    char buf[MAX_BUF];
    size_t pos = 0;
    bool in_info = false;
    while (string_get_word(server->cert, &pos, '\n', VS(buf), 0)) {
        char *cp = buf;
        string_skip_whitespace(cp);
        string_strip_newline(cp);

        if (*cp == '\0') {
            continue;
        }

        if (strcmp(cp, cert_begin_str) == 0) {
            in_info = true;
            continue;
        } else if (!in_info) {
            continue;
        } else if (strcmp(cp, cert_end_str) == 0) {
            break;
        }

        char *cps[2];
        if (string_split(cp, cps, arraysize(cps), ':') != arraysize(cps)) {
            LOG(ERROR, "Parsing error");
            continue;
        }

        string_tolower(cps[0]);
        string_skip_whitespace(cps[1]);
        const char *key = cps[0];
        const char *value = cps[1];
        char **content = NULL;
        if (strcmp(key, "name") == 0) {
            content = &info->name;
        } else if (strcmp(key, "hostname") == 0) {
            content = &info->hostname;
        } else if (strcmp(key, "ipv4 address") == 0) {
            content = &info->ipv4_address;
        } else if (strcmp(key, "ipv6 address") == 0) {
            content = &info->ipv6_address;
        } else if (strcmp(key, "public key") == 0) {
            content = &info->pubkey;
        } else if (strcmp(key, "port") == 0) {
            info->port = atoi(value);
        } else if (strcmp(key, "crypto port") == 0) {
            info->port_crypto = atoi(value);
        } else {
            LOG(DEVEL, "Unrecognized key: %s", key);
            continue;
        }

        if (content != NULL) {
            StringBuffer *sb = stringbuffer_new();

            if (*content != NULL) {
                stringbuffer_append_string(sb, *content);
                stringbuffer_append_char(sb, '\n');
                efree(*content);
            }

            stringbuffer_append_string(sb, value);
            *content = stringbuffer_finish(sb);
        }
    }

    /* Ensure we got the data we need. */
    if (info->name == NULL ||
        info->hostname == NULL ||
        info->pubkey == NULL ||
        info->port_crypto <= 0 ||
        (info->ipv4_address == NULL) != (info->ipv6_address == NULL)) {
        LOG(ERROR,
            "Certificate is missing required data.");
        goto error;
    }

    /* Ensure certificate attributes match the advertised ones. */
    if (strcmp(info->hostname, server->hostname) != 0) {
        LOG(ERROR,
            "Certificate hostname does not match advertised hostname.");
        goto error;
    }

    if (strcmp(info->name, server->name) != 0) {
        LOG(ERROR,
            "Certificate name does not match advertised name.");
        goto error;
    }

    if (info->port != server->port) {
        LOG(ERROR,
            "Certificate port does not match advertised port.");
        goto error;
    }

    if (info->port_crypto != server->port_crypto) {
        LOG(ERROR,
            "Certificate crypto port does not match advertised crypto port.");
        goto error;
    }

    server->cert_info = info;
    return true;

error:
    metaserver_cert_free(info);
    return false;
}
示例#2
0
QUVIcode verify_wrapper(_quvi_t q, _quvi_llst_node_t l)
{
  static const char *scheme = "http://";
  _quvi_media_url_t m;
  _quvi_net_t n;
  QUVIcode rc;
  char b[8];

  rc = QUVI_OK;

  m = (_quvi_media_url_t) l->data;
  m->url = from_html_entities(m->url);

  memset(&b, 0, sizeof(b));

  if (strcmp(strncpy(b, m->url, strlen(scheme)), scheme) != 0)
    return (QUVI_OK); /* Ignore non-HTTP URLs */

  if (q->status_func)
    {
      if (q->status_func(_makelong(QUVISTATUS_VERIFY, 0), 0) != QUVI_OK)
        return (QUVI_ABORTEDBYCALLBACK);
    }

  n = new_net_handle();
  if (!n)
    return (QUVI_MEM);

  freprintf(&n->url, "%s", m->url);

  if (q->verify_func)
    rc = q->verify_func(n);
  else
    rc = curl_verify(q, n);

  if (rc == QUVI_OK)
    {
      freprintf(&m->content_type, "%s", n->verify.content_type);

      m->length = n->verify.content_length;

      rc = run_lua_suffix_func(q, m); /* content-type -> suffix */

      if (q->status_func)
        {
          const long param =
            _makelong(QUVISTATUS_VERIFY, QUVISTATUSTYPE_DONE);

          rc = q->status_func(param, 0);
        }
    }
  else
    {
      if (n->errmsg)
        freprintf(&q->errmsg, "%s", n->errmsg);
    }

  q->resp_code = n->resp_code;

  free_net_handle(&n);

  return (rc);
}