示例#1
0
static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx )
{
    pjsip_proxy_authenticate_hdr *hdr = 
        pjsip_proxy_authenticate_hdr_create(ctx->pool);
    int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
    return (pjsip_hdr*)hdr;
}
static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,
								     const pjsip_www_authenticate_hdr *rhs)
{
    /* This function also serves Proxy-Authenticate header. */
    pjsip_www_authenticate_hdr *hdr;
    if (rhs->type == PJSIP_H_WWW_AUTHENTICATE)
	hdr = pjsip_www_authenticate_hdr_create(pool);
    else
	hdr = pjsip_proxy_authenticate_hdr_create(pool);

    pj_strdup(pool, &hdr->scheme, &rhs->scheme);

    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {
	pj_strdup(pool, &hdr->challenge.digest.realm, &rhs->challenge.digest.realm);
	pj_strdup(pool, &hdr->challenge.digest.domain, &rhs->challenge.digest.domain);
	pj_strdup(pool, &hdr->challenge.digest.nonce, &rhs->challenge.digest.nonce);
	pj_strdup(pool, &hdr->challenge.digest.opaque, &rhs->challenge.digest.opaque);
	hdr->challenge.digest.stale = rhs->challenge.digest.stale;
	pj_strdup(pool, &hdr->challenge.digest.algorithm, &rhs->challenge.digest.algorithm);
	pj_strdup(pool, &hdr->challenge.digest.qop, &rhs->challenge.digest.qop);
	pjsip_param_clone(pool, &hdr->challenge.digest.other_param, 
			  &rhs->challenge.digest.other_param);
    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {
	pj_assert(0);
	return NULL;
    } else {
	pj_assert(0);
	return NULL;
    }

    return hdr;

}
示例#3
0
/*
 * Add authentication challenge headers to the outgoing response in tdata. 
 * Application may specify its customized nonce and opaque for the challenge, 
 * or can leave the value to NULL to make the function fills them in with 
 * random characters.
 */
PJ_DEF(pj_status_t) pjsip_auth_srv_challenge(  pjsip_auth_srv *auth_srv,
					       const pj_str_t *qop,
					       const pj_str_t *nonce,
					       const pj_str_t *opaque,
					       pj_bool_t stale,
					       pjsip_tx_data *tdata)
{
    pjsip_www_authenticate_hdr *hdr;
    char nonce_buf[16];
    pj_str_t random;

    PJ_ASSERT_RETURN( auth_srv && tdata, PJ_EINVAL );

    random.ptr = nonce_buf;
    random.slen = sizeof(nonce_buf);

    /* Create the header. */
    if (auth_srv->is_proxy)
	hdr = pjsip_proxy_authenticate_hdr_create(tdata->pool);
    else
	hdr = pjsip_www_authenticate_hdr_create(tdata->pool);

    /* Initialize header. 
     * Note: only support digest authentication now.
     */
    hdr->scheme = pjsip_DIGEST_STR;
    hdr->challenge.digest.algorithm = pjsip_MD5_STR;
    if (nonce) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, nonce);
    } else {
	pj_create_random_string(nonce_buf, sizeof(nonce_buf));
	pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random);
    }
    if (opaque) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, opaque);
    } else {
	pj_create_random_string(nonce_buf, sizeof(nonce_buf));
	pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
    }
    if (qop) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.qop, qop);
    } else {
	hdr->challenge.digest.qop.slen = 0;
    }
    pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &auth_srv->realm);
    hdr->challenge.digest.stale = stale;

    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);

    return PJ_SUCCESS;
}
示例#4
0
void create_challenge(pjsip_digest_credential* credentials,
                      pj_bool_t stale,
                      std::string resync,
                      pjsip_rx_data* rdata,
                      pjsip_tx_data* tdata)
{
  // Get the public and private identities from the request.
  std::string impi;
  std::string impu;
  std::string nonce;

  PJUtils::get_impi_and_impu(rdata, impi, impu);
  // Set up the authorization type, following Annex P.4 of TS 33.203.  Currently
  // only support AKA and SIP Digest, so only implement the subset of steps
  // required to distinguish between the two.
  std::string auth_type;
  if (credentials != NULL)
  {
    pjsip_param* integrity =
           pjsip_param_find(&credentials->other_param,
                            &STR_INTEGRITY_PROTECTED);

    if ((integrity != NULL) &&
        ((pj_stricmp(&integrity->value, &STR_YES) == 0) ||
         (pj_stricmp(&integrity->value, &STR_NO) == 0)))
    {
      // Authentication scheme is AKA.
      auth_type = "aka";
    }
  }

  // Get the Authentication Vector from the HSS.
  rapidjson::Document* av = NULL;
  HTTPCode http_code = hss->get_auth_vector(impi, impu, auth_type, resync, av, get_trail(rdata));

  if ((av != NULL) &&
      (!verify_auth_vector(av, impi, get_trail(rdata))))
  {
    // Authentication Vector is badly formed.
    delete av;
    av = NULL;
  }

  if (av != NULL)
  {
    // Retrieved a valid authentication vector, so generate the challenge.
    TRC_DEBUG("Valid AV - generate challenge");
    char buf[16];
    pj_str_t random;
    random.ptr = buf;
    random.slen = sizeof(buf);

    pjsip_www_authenticate_hdr* hdr;
    if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD)
    {
      TRC_DEBUG("Create WWW-Authenticate header");
      hdr = pjsip_www_authenticate_hdr_create(tdata->pool);
    }
    else
    {
      TRC_DEBUG("Create Proxy-Authenticate header");
      hdr = pjsip_proxy_authenticate_hdr_create(tdata->pool);
    }

    // Set up common fields for Digest and AKA cases (both are considered
    // Digest authentication).
    hdr->scheme = STR_DIGEST;

    if (av->HasMember("aka"))
    {
      // AKA authentication.
      TRC_DEBUG("Add AKA information");

      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE_AKA, 0);
      SAS::report_event(event);

      rapidjson::Value& aka = (*av)["aka"];

      // Use default realm for AKA as not specified in the AV.
      pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &aka_realm);
      hdr->challenge.digest.algorithm = STR_AKAV1_MD5;

      if ((aka.HasMember("challenge")) &&
          (aka["challenge"].IsString()))
      {
        nonce = aka["challenge"].GetString();
      }

      pj_strdup2(tdata->pool, &hdr->challenge.digest.nonce, nonce.c_str());
      pj_create_random_string(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
      hdr->challenge.digest.qop = STR_AUTH;
      hdr->challenge.digest.stale = stale;

      // Add the cryptography key parameter.
      pjsip_param* ck_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param));
      ck_param->name = STR_CK;
      std::string cryptkey = "";
      if ((aka.HasMember("cryptkey")) &&
          (aka["cryptkey"].IsString()))
      {
        cryptkey = aka["cryptkey"].GetString();
      }
      std::string ck = "\"" + cryptkey + "\"";
      pj_strdup2(tdata->pool, &ck_param->value, ck.c_str());
      pj_list_insert_before(&hdr->challenge.digest.other_param, ck_param);

      // Add the integrity key parameter.
      pjsip_param* ik_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param));
      ik_param->name = STR_IK;
      std::string integritykey = "";
      if ((aka.HasMember("integritykey")) &&
          (aka["integritykey"].IsString()))
      {
        integritykey = aka["integritykey"].GetString();
      }
      std::string ik = "\"" + integritykey + "\"";
      pj_strdup2(tdata->pool, &ik_param->value, ik.c_str());
      pj_list_insert_before(&hdr->challenge.digest.other_param, ik_param);
    }
    else
    {
      // Digest authentication.
      TRC_DEBUG("Add Digest information");

      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE_DIGEST, 0);
      SAS::report_event(event);

      rapidjson::Value& digest = (*av)["digest"];
      std::string realm = "";
      if ((digest.HasMember("realm")) &&
          (digest["realm"].IsString()))
      {
        realm = digest["realm"].GetString();
      }

      std::string qop = "";
      if ((digest.HasMember("qop")) &&
          (digest["qop"].IsString()))
      {
        qop = digest["qop"].GetString();
      }
      pj_strdup2(tdata->pool, &hdr->challenge.digest.realm, realm.c_str());
      hdr->challenge.digest.algorithm = STR_MD5;
      pj_create_random_string(buf, sizeof(buf));
      nonce.assign(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random);
      pj_create_random_string(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
      pj_strdup2(tdata->pool, &hdr->challenge.digest.qop, qop.c_str());
      hdr->challenge.digest.stale = stale;
    }

    // Add the header to the message.
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);

    // Store the branch parameter in memcached for correlation purposes
    pjsip_via_hdr* via_hdr = (pjsip_via_hdr*)pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
    std::string branch = (via_hdr != NULL) ? PJUtils::pj_str_to_string(&via_hdr->branch_param) : "";

    rapidjson::Value branch_value;
    branch_value.SetString(branch.c_str(), (*av).GetAllocator());
    (*av).AddMember("branch", branch_value, (*av).GetAllocator());

    // Write the authentication vector (as a JSON string) into the AV store.
    TRC_DEBUG("Write AV to store");
    uint64_t cas = 0;
    Store::Status status = av_store->set_av(impi, nonce, av, cas, get_trail(rdata));
    if (status == Store::OK)
    {
      // We've written the AV into the store, so need to set a Chronos
      // timer so that an AUTHENTICATION_TIMEOUT SAR is sent to the
      // HSS when it expires.
      std::string timer_id;
      std::string chronos_body = "{\"impi\": \"" + impi + "\", \"impu\": \"" + impu +"\", \"nonce\": \"" + nonce +"\"}";
      TRC_DEBUG("Sending %s to Chronos to set AV timer", chronos_body.c_str());
      chronos->send_post(timer_id, 30, "/authentication-timeout", chronos_body, get_trail(rdata));
    }

    delete av;
  }
  else
  {
    // If we couldn't get the AV because a downstream node is overloaded then don't return
    // a 4xx error to the client.
    if ((http_code == HTTP_SERVER_UNAVAILABLE) || (http_code == HTTP_GATEWAY_TIMEOUT))
    {
      TRC_DEBUG("Downstream node is overloaded or unresponsive, unable to get Authentication vector");
      tdata->msg->line.status.code = PJSIP_SC_SERVER_TIMEOUT;
      tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_SERVER_TIMEOUT);
      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_FAILED_OVERLOAD, 0);
      SAS::report_event(event);
    }
    else
    {
      TRC_DEBUG("Failed to get Authentication vector");
      tdata->msg->line.status.code = PJSIP_SC_FORBIDDEN;
      tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_FORBIDDEN);
      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_FAILED_NO_AV, 0);
      SAS::report_event(event);
    }

    pjsip_tx_data_invalidate_msg(tdata);
  }
}