res_pjsip_authenticator_digest.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Mark Michelson <mmichelson@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. #include "asterisk.h"
  19. #include <pjsip.h>
  20. #include "asterisk/res_pjsip.h"
  21. #include "asterisk/logger.h"
  22. #include "asterisk/module.h"
  23. #include "asterisk/strings.h"
  24. #include "asterisk/test.h"
  25. /*** MODULEINFO
  26. <depend>pjproject</depend>
  27. <depend>res_pjsip</depend>
  28. <support_level>core</support_level>
  29. ***/
  30. static char default_realm[AST_SIP_AUTH_MAX_REALM_LENGTH + 1];
  31. AO2_GLOBAL_OBJ_STATIC(entity_id);
  32. /*!
  33. * \brief Determine if authentication is required
  34. *
  35. * Authentication is required if the endpoint has at least one auth
  36. * section specified
  37. */
  38. static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
  39. {
  40. RAII_VAR(struct ast_sip_endpoint *, artificial, ast_sip_get_artificial_endpoint(), ao2_cleanup);
  41. return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
  42. }
  43. static void auth_store_cleanup(void *data)
  44. {
  45. struct ast_sip_auth **auth = data;
  46. ao2_cleanup(*auth);
  47. ast_free(data);
  48. }
  49. /*!
  50. * \brief Thread-local storage for \ref ast_sip_auth
  51. *
  52. * The PJSIP authentication API is a bit annoying. When you set
  53. * up an authentication server, you specify a lookup callback to
  54. * call into when verifying incoming credentials. The problem
  55. * with this callback is that it only gives you the realm and
  56. * authentication username. In 2.0.5, there is a new version of
  57. * the callback you can use that gives the pjsip_rx_data in
  58. * addition.
  59. *
  60. * Unfortunately, the data we actually \b need is the
  61. * \ref ast_sip_auth we are currently observing. So we have two
  62. * choices:
  63. * 1) Use the current PJSIP API and use thread-local storage
  64. * to temporarily store our SIP authentication information. Then
  65. * in the callback, we can retrieve the authentication info and
  66. * use as needed. Given our threading model, this is safe.
  67. * 2) Use the 2.0.5 API and temporarily store the authentication
  68. * information in the rdata's endpoint_info. Then in the callback,
  69. * we can retrieve the authentication info from the rdata.
  70. *
  71. * I've chosen option 1 since it does not require backporting
  72. * any APIs from future versions of PJSIP, plus I feel the
  73. * thread-local option is a bit cleaner.
  74. */
  75. AST_THREADSTORAGE_CUSTOM(auth_store, NULL, auth_store_cleanup);
  76. /*!
  77. * \brief Store shallow copy authentication information in thread-local storage
  78. */
  79. static int store_auth(const struct ast_sip_auth *auth)
  80. {
  81. const struct ast_sip_auth **pointing;
  82. pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
  83. if (!pointing) {
  84. return -1;
  85. }
  86. *pointing = auth;
  87. return 0;
  88. }
  89. /*!
  90. * \brief Remove shallow copy authentication information from thread-local storage
  91. */
  92. static int remove_auth(void)
  93. {
  94. struct ast_sip_auth **pointing;
  95. pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
  96. if (!pointing) {
  97. return -1;
  98. }
  99. *pointing = NULL;
  100. return 0;
  101. }
  102. /*!
  103. * \brief Retrieve shallow copy authentication information from thread-local storage
  104. */
  105. static const struct ast_sip_auth *get_auth(void)
  106. {
  107. struct ast_sip_auth **auth;
  108. auth = ast_threadstorage_get(&auth_store, sizeof(auth));
  109. if (auth) {
  110. return *auth;
  111. }
  112. return NULL;
  113. }
  114. /*!
  115. * \brief Lookup callback for authentication verification
  116. *
  117. * This function is called when we call pjsip_auth_srv_verify(). It
  118. * expects us to verify that the realm and account name from the
  119. * Authorization header is correct. We are then supposed to supply
  120. * a password or MD5 sum of credentials.
  121. *
  122. * \param pool A memory pool we can use for allocations
  123. * \param realm The realm from the Authorization header
  124. * \param acc_name the user from the Authorization header
  125. * \param[out] info The credentials we need to fill in
  126. * \retval PJ_SUCCESS Successful authentication
  127. * \retval other Unsuccessful
  128. */
  129. static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm,
  130. const pj_str_t *acc_name, pjsip_cred_info *info)
  131. {
  132. const struct ast_sip_auth *auth;
  133. auth = get_auth();
  134. if (!auth) {
  135. return PJSIP_SC_FORBIDDEN;
  136. }
  137. if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
  138. return PJSIP_SC_FORBIDDEN;
  139. }
  140. if (pj_strcmp2(realm, auth->realm)) {
  141. return PJSIP_SC_FORBIDDEN;
  142. }
  143. if (pj_strcmp2(acc_name, auth->auth_user)) {
  144. return PJSIP_SC_FORBIDDEN;
  145. }
  146. pj_strdup2(pool, &info->realm, auth->realm);
  147. pj_strdup2(pool, &info->username, auth->auth_user);
  148. switch (auth->type) {
  149. case AST_SIP_AUTH_TYPE_USER_PASS:
  150. pj_strdup2(pool, &info->data, auth->auth_pass);
  151. info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
  152. break;
  153. case AST_SIP_AUTH_TYPE_MD5:
  154. pj_strdup2(pool, &info->data, auth->md5_creds);
  155. info->data_type = PJSIP_CRED_DATA_DIGEST;
  156. break;
  157. default:
  158. return PJSIP_SC_FORBIDDEN;
  159. }
  160. return PJ_SUCCESS;
  161. }
  162. /*!
  163. * \brief Calculate a nonce
  164. *
  165. * We use this in order to create authentication challenges. We also use this in order
  166. * to verify that an incoming request with credentials could be in response to one
  167. * of our challenges.
  168. *
  169. * The nonce is calculated from a timestamp, the source IP address, the source port, a
  170. * unique ID for us, and the realm. This helps to ensure that the incoming request
  171. * is from the same source that the nonce was calculated for. Including the realm
  172. * ensures that multiple challenges to the same request have different nonces.
  173. *
  174. * \param nonce
  175. * \param timestamp A UNIX timestamp expressed as a string
  176. * \param rdata The incoming request
  177. * \param realm The realm for which authentication should occur
  178. */
  179. static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
  180. {
  181. struct ast_str *str = ast_str_alloca(256);
  182. RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
  183. char hash[33];
  184. /*
  185. * Note you may be tempted to think why not include the port. The reason
  186. * is that when using TCP the port can potentially differ from before.
  187. */
  188. ast_str_append(&str, 0, "%s", timestamp);
  189. ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
  190. ast_str_append(&str, 0, ":%s", eid);
  191. ast_str_append(&str, 0, ":%s", realm);
  192. ast_md5_hash(hash, ast_str_buffer(str));
  193. ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
  194. return 0;
  195. }
  196. /*!
  197. * \brief Ensure that a nonce on an incoming request is sane.
  198. *
  199. * The nonce in an incoming Authorization header needs to pass some scrutiny in order
  200. * for us to consider accepting it. What we do is re-build a nonce based on request
  201. * data and a realm and see if it matches the nonce they sent us.
  202. * \param candidate The nonce on an incoming request
  203. * \param rdata The incoming request
  204. * \param auth The auth credentials we are trying to match against.
  205. * \retval 0 Nonce does not pass validity checks
  206. * \retval 1 Nonce passes validity check
  207. */
  208. static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
  209. {
  210. char *copy = ast_strdupa(candidate);
  211. char *timestamp = strsep(&copy, "/");
  212. int timestamp_int;
  213. time_t now = time(NULL);
  214. struct ast_str *calculated = ast_str_alloca(64);
  215. if (!copy) {
  216. /* Clearly a bad nonce! */
  217. return 0;
  218. }
  219. if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
  220. return 0;
  221. }
  222. if ((int) now - timestamp_int > auth->nonce_lifetime) {
  223. return 0;
  224. }
  225. build_nonce(&calculated, timestamp, rdata, auth->realm);
  226. ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
  227. if (strcmp(ast_str_buffer(calculated), candidate)) {
  228. return 0;
  229. }
  230. return 1;
  231. }
  232. static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
  233. {
  234. struct pjsip_authorization_hdr *auth_hdr = (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
  235. int challenge_found = 0;
  236. char nonce[64];
  237. while ((auth_hdr = (pjsip_authorization_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, auth_hdr->next))) {
  238. ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
  239. if (check_nonce(nonce, rdata, auth) && !pj_strcmp2(&auth_hdr->credential.digest.realm, auth->realm)) {
  240. challenge_found = 1;
  241. break;
  242. }
  243. }
  244. return challenge_found;
  245. }
  246. /*!
  247. * \brief Common code for initializing a pjsip_auth_srv
  248. */
  249. static void setup_auth_srv(pj_pool_t *pool, pjsip_auth_srv *auth_server, const char *realm)
  250. {
  251. pj_str_t realm_str;
  252. pj_cstr(&realm_str, realm);
  253. pjsip_auth_srv_init(pool, auth_server, &realm_str, digest_lookup, 0);
  254. }
  255. /*!
  256. * \brief Result of digest verification
  257. */
  258. enum digest_verify_result {
  259. /*! Authentication credentials incorrect */
  260. AUTH_FAIL = 0,
  261. /*! Authentication credentials correct */
  262. AUTH_SUCCESS,
  263. /*! Authentication credentials correct but nonce mismatch */
  264. AUTH_STALE,
  265. /*! Authentication credentials were not provided */
  266. AUTH_NOAUTH,
  267. };
  268. static char *verify_result_str[] = {
  269. "FAIL",
  270. "SUCCESS",
  271. "STALE",
  272. "NOAUTH"
  273. };
  274. /*!
  275. * \brief astobj2 callback for verifying incoming credentials
  276. *
  277. * \param auth The ast_sip_auth to check against
  278. * \param rdata The incoming request
  279. * \param pool A pool to use for the auth server
  280. * \return CMP_MATCH on successful authentication
  281. * \return 0 on failed authentication
  282. */
  283. static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
  284. {
  285. pj_status_t authed;
  286. int response_code;
  287. pjsip_auth_srv auth_server;
  288. int stale = 0;
  289. int res = AUTH_FAIL;
  290. if (!find_challenge(rdata, auth)) {
  291. /* Couldn't find a challenge with a sane nonce.
  292. * Nonce mismatch may just be due to staleness.
  293. */
  294. stale = 1;
  295. }
  296. setup_auth_srv(pool, &auth_server, auth->realm);
  297. store_auth(auth);
  298. authed = pjsip_auth_srv_verify(&auth_server, rdata, &response_code);
  299. remove_auth();
  300. if (authed == PJ_SUCCESS) {
  301. if (stale) {
  302. res = AUTH_STALE;
  303. } else {
  304. res = AUTH_SUCCESS;
  305. }
  306. }
  307. if (authed == PJSIP_EAUTHNOAUTH) {
  308. res = AUTH_NOAUTH;
  309. }
  310. ast_debug(3, "Realm: %s Username: %s Result: %s\n",
  311. auth->realm, auth->auth_user, verify_result_str[res]);
  312. ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
  313. "Realm: %s\r\n"
  314. "Username: %s\r\n"
  315. "Status: %s",
  316. auth->realm, auth->auth_user, verify_result_str[res]);
  317. return res;
  318. }
  319. /*!
  320. * \brief astobj2 callback for adding digest challenges to responses
  321. *
  322. * \param realm An auth's realm to build a challenge from
  323. * \param tdata The response to add the challenge to
  324. * \param rdata The request the challenge is in response to
  325. * \param is_stale Indicates whether nonce on incoming request was stale
  326. */
  327. static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
  328. {
  329. pj_str_t qop;
  330. pj_str_t pj_nonce;
  331. pjsip_auth_srv auth_server;
  332. struct ast_str *nonce = ast_str_alloca(256);
  333. char time_buf[32];
  334. time_t timestamp = time(NULL);
  335. snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
  336. build_nonce(&nonce, time_buf, rdata, realm);
  337. setup_auth_srv(tdata->pool, &auth_server, realm);
  338. pj_cstr(&pj_nonce, ast_str_buffer(nonce));
  339. pj_cstr(&qop, "auth");
  340. pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
  341. }
  342. /*!
  343. * \brief Check authentication using Digest scheme
  344. *
  345. * This function will check an incoming message against configured authentication
  346. * options. If \b any of the incoming Authorization headers result in successful
  347. * authentication, then authentication is considered successful.
  348. *
  349. * \see ast_sip_check_authentication
  350. */
  351. static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint,
  352. pjsip_rx_data *rdata, pjsip_tx_data *tdata)
  353. {
  354. struct ast_sip_auth **auths;
  355. struct ast_sip_auth **auths_shallow;
  356. enum digest_verify_result *verify_res;
  357. struct ast_sip_endpoint *artificial_endpoint;
  358. enum ast_sip_check_auth_result res;
  359. int idx;
  360. int is_artificial;
  361. int failures = 0;
  362. size_t auth_size;
  363. auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
  364. ast_assert(0 < auth_size);
  365. auths = ast_alloca(auth_size * sizeof(*auths));
  366. verify_res = ast_alloca(auth_size * sizeof(*verify_res));
  367. artificial_endpoint = ast_sip_get_artificial_endpoint();
  368. if (!artificial_endpoint) {
  369. /* Should not happen except possibly if we are shutting down. */
  370. return AST_SIP_AUTHENTICATION_ERROR;
  371. }
  372. is_artificial = endpoint == artificial_endpoint;
  373. ao2_ref(artificial_endpoint, -1);
  374. if (is_artificial) {
  375. ast_assert(auth_size == 1);
  376. auths[0] = ast_sip_get_artificial_auth();
  377. if (!auths[0]) {
  378. /* Should not happen except possibly if we are shutting down. */
  379. return AST_SIP_AUTHENTICATION_ERROR;
  380. }
  381. } else {
  382. memset(auths, 0, auth_size * sizeof(*auths));
  383. if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
  384. res = AST_SIP_AUTHENTICATION_ERROR;
  385. goto cleanup;
  386. }
  387. }
  388. /* Setup shallow copy of auths */
  389. if (ast_strlen_zero(default_realm)) {
  390. auths_shallow = auths;
  391. } else {
  392. /*
  393. * Set default realm on a shallow copy of the authentication
  394. * objects that don't have a realm set.
  395. */
  396. auths_shallow = ast_alloca(auth_size * sizeof(*auths_shallow));
  397. for (idx = 0; idx < auth_size; ++idx) {
  398. if (ast_strlen_zero(auths[idx]->realm)) {
  399. /*
  400. * Make a shallow copy and set the default realm on it.
  401. *
  402. * The stack allocation is OK here. Normally this will
  403. * loop one time. If you have multiple auths then you
  404. * shouldn't need more auths than the normal complement
  405. * of fingers and toes. Otherwise, you should check
  406. * your sanity for setting up your system up that way.
  407. */
  408. auths_shallow[idx] = ast_alloca(sizeof(**auths_shallow));
  409. memcpy(auths_shallow[idx], auths[idx], sizeof(**auths_shallow));
  410. *((char **) (&auths_shallow[idx]->realm)) = default_realm;
  411. ast_debug(3, "Using default realm '%s' on incoming auth '%s'.\n",
  412. default_realm, ast_sorcery_object_get_id(auths_shallow[idx]));
  413. } else {
  414. auths_shallow[idx] = auths[idx];
  415. }
  416. }
  417. }
  418. for (idx = 0; idx < auth_size; ++idx) {
  419. verify_res[idx] = verify(auths_shallow[idx], rdata, tdata->pool);
  420. if (verify_res[idx] == AUTH_SUCCESS) {
  421. res = AST_SIP_AUTHENTICATION_SUCCESS;
  422. goto cleanup;
  423. }
  424. if (verify_res[idx] == AUTH_FAIL) {
  425. failures++;
  426. }
  427. }
  428. for (idx = 0; idx < auth_size; ++idx) {
  429. challenge(auths_shallow[idx]->realm, tdata, rdata, verify_res[idx] == AUTH_STALE);
  430. }
  431. if (failures == auth_size) {
  432. res = AST_SIP_AUTHENTICATION_FAILED;
  433. } else {
  434. res = AST_SIP_AUTHENTICATION_CHALLENGE;
  435. }
  436. cleanup:
  437. ast_sip_cleanup_auths(auths, auth_size);
  438. return res;
  439. }
  440. static struct ast_sip_authenticator digest_authenticator = {
  441. .requires_authentication = digest_requires_authentication,
  442. .check_authentication = digest_check_auth,
  443. };
  444. static int build_entity_id(void)
  445. {
  446. char *eid;
  447. eid = ao2_alloc(AST_UUID_STR_LEN, NULL);
  448. if (!eid) {
  449. return -1;
  450. }
  451. ast_uuid_generate_str(eid, AST_UUID_STR_LEN);
  452. ao2_global_obj_replace_unref(entity_id, eid);
  453. ao2_ref(eid, -1);
  454. return 0;
  455. }
  456. static void global_loaded(const char *object_type)
  457. {
  458. ast_sip_get_default_realm(default_realm, sizeof(default_realm));
  459. }
  460. /*! \brief Observer which is used to update our default_realm when the global setting changes */
  461. static struct ast_sorcery_observer global_observer = {
  462. .loaded = global_loaded,
  463. };
  464. static int reload_module(void)
  465. {
  466. if (build_entity_id()) {
  467. return -1;
  468. }
  469. return 0;
  470. }
  471. static int load_module(void)
  472. {
  473. if (build_entity_id()) {
  474. return AST_MODULE_LOAD_DECLINE;
  475. }
  476. ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer);
  477. ast_sorcery_reload_object(ast_sip_get_sorcery(), "global");
  478. if (ast_sip_register_authenticator(&digest_authenticator)) {
  479. ao2_global_obj_release(entity_id);
  480. return AST_MODULE_LOAD_DECLINE;
  481. }
  482. return AST_MODULE_LOAD_SUCCESS;
  483. }
  484. static int unload_module(void)
  485. {
  486. ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer);
  487. ast_sip_unregister_authenticator(&digest_authenticator);
  488. ao2_global_obj_release(entity_id);
  489. return 0;
  490. }
  491. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication resource",
  492. .support_level = AST_MODULE_SUPPORT_CORE,
  493. .load = load_module,
  494. .unload = unload_module,
  495. .reload = reload_module,
  496. .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
  497. .requires = "res_pjsip",
  498. );