vtls_scache.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. /* This file is for implementing all "generic" SSL functions that all libcurl
  25. internals should use. It is then responsible for calling the proper
  26. "backend" function.
  27. SSL-functions in libcurl should call functions in this source file, and not
  28. to any specific SSL-layer.
  29. Curl_ssl_ - prefix for generic ones
  30. Note that this source code uses the functions of the configured SSL
  31. backend via the global Curl_ssl instance.
  32. "SSL/TLS Strong Encryption: An Introduction"
  33. https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
  34. */
  35. #include "curl_setup.h"
  36. #ifdef USE_SSL
  37. #ifdef HAVE_SYS_TYPES_H
  38. #include <sys/types.h>
  39. #endif
  40. #ifdef HAVE_SYS_STAT_H
  41. #include <sys/stat.h>
  42. #endif
  43. #ifdef HAVE_FCNTL_H
  44. #include <fcntl.h>
  45. #endif
  46. #include "urldata.h"
  47. #include "cfilters.h"
  48. #include "vtls.h" /* generic SSL protos etc */
  49. #include "vtls_int.h"
  50. #include "vtls_scache.h"
  51. #include "strcase.h"
  52. #include "url.h"
  53. #include "llist.h"
  54. #include "share.h"
  55. #include "curl_trc.h"
  56. #include "curl_sha256.h"
  57. #include "warnless.h"
  58. #include "curl_printf.h"
  59. #include "strdup.h"
  60. /* The last #include files should be: */
  61. #include "curl_memory.h"
  62. #include "memdebug.h"
  63. /* a peer+tls-config we cache sessions for */
  64. struct Curl_ssl_scache_peer {
  65. char *ssl_peer_key; /* id for peer + relevant TLS configuration */
  66. char *clientcert;
  67. char *srp_username;
  68. char *srp_password;
  69. struct Curl_llist sessions;
  70. void *sobj; /* object instance or NULL */
  71. Curl_ssl_scache_obj_dtor *sobj_free; /* free `sobj` callback */
  72. unsigned char key_salt[CURL_SHA256_DIGEST_LENGTH]; /* for entry export */
  73. unsigned char key_hmac[CURL_SHA256_DIGEST_LENGTH]; /* for entry export */
  74. size_t max_sessions;
  75. long age; /* just a number, the higher the more recent */
  76. BIT(hmac_set); /* if key_salt and key_hmac are present */
  77. };
  78. struct Curl_ssl_scache {
  79. struct Curl_ssl_scache_peer *peers;
  80. size_t peer_count;
  81. int default_lifetime_secs;
  82. long age;
  83. };
  84. static void cf_ssl_scache_clear_session(struct Curl_ssl_session *s)
  85. {
  86. if(s->sdata) {
  87. free((void *)s->sdata);
  88. s->sdata = NULL;
  89. }
  90. s->sdata_len = 0;
  91. if(s->quic_tp) {
  92. free((void *)s->quic_tp);
  93. s->quic_tp = NULL;
  94. }
  95. s->quic_tp_len = 0;
  96. s->ietf_tls_id = 0;
  97. s->time_received = 0;
  98. s->lifetime_secs = 0;
  99. Curl_safefree(s->alpn);
  100. }
  101. static void cf_ssl_scache_sesssion_ldestroy(void *udata, void *s)
  102. {
  103. (void)udata;
  104. cf_ssl_scache_clear_session(s);
  105. free(s);
  106. }
  107. CURLcode
  108. Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len,
  109. int ietf_tls_id, const char *alpn,
  110. curl_off_t time_received, long lifetime_secs,
  111. size_t earlydata_max,
  112. struct Curl_ssl_session **psession)
  113. {
  114. return Curl_ssl_session_create2(sdata, sdata_len, ietf_tls_id, alpn,
  115. time_received, lifetime_secs,
  116. earlydata_max, NULL, 0, psession);
  117. }
  118. CURLcode
  119. Curl_ssl_session_create2(unsigned char *sdata, size_t sdata_len,
  120. int ietf_tls_id, const char *alpn,
  121. curl_off_t time_received, long lifetime_secs,
  122. size_t earlydata_max,
  123. unsigned char *quic_tp, size_t quic_tp_len,
  124. struct Curl_ssl_session **psession)
  125. {
  126. struct Curl_ssl_session *s;
  127. if(!sdata || !sdata_len) {
  128. free(sdata);
  129. return CURLE_BAD_FUNCTION_ARGUMENT;
  130. }
  131. *psession = NULL;
  132. s = calloc(1, sizeof(*s));
  133. if(!s) {
  134. free(sdata);
  135. free(quic_tp);
  136. return CURLE_OUT_OF_MEMORY;
  137. }
  138. s->ietf_tls_id = ietf_tls_id;
  139. s->time_received = time_received;
  140. if(lifetime_secs < 0)
  141. lifetime_secs = -1; /* unknown */
  142. else if((s->ietf_tls_id == CURL_IETF_PROTO_TLS1_3) &&
  143. (lifetime_secs > CURL_SCACHE_MAX_13_LIFETIME_SEC))
  144. lifetime_secs = CURL_SCACHE_MAX_13_LIFETIME_SEC;
  145. else if(lifetime_secs > CURL_SCACHE_MAX_12_LIFETIME_SEC)
  146. lifetime_secs = CURL_SCACHE_MAX_12_LIFETIME_SEC;
  147. s->lifetime_secs = (int)lifetime_secs;
  148. s->earlydata_max = earlydata_max;
  149. s->sdata = sdata;
  150. s->sdata_len = sdata_len;
  151. s->quic_tp = quic_tp;
  152. s->quic_tp_len = quic_tp_len;
  153. if(alpn) {
  154. s->alpn = strdup(alpn);
  155. if(!s->alpn) {
  156. cf_ssl_scache_sesssion_ldestroy(NULL, s);
  157. return CURLE_OUT_OF_MEMORY;
  158. }
  159. }
  160. *psession = s;
  161. return CURLE_OK;
  162. }
  163. void Curl_ssl_session_destroy(struct Curl_ssl_session *s)
  164. {
  165. if(s) {
  166. /* if in the list, the list destructor takes care of it */
  167. if(Curl_node_llist(&s->list))
  168. Curl_node_remove(&s->list);
  169. else {
  170. cf_ssl_scache_sesssion_ldestroy(NULL, s);
  171. }
  172. }
  173. }
  174. static void cf_ssl_scache_clear_peer(struct Curl_ssl_scache_peer *peer)
  175. {
  176. Curl_llist_destroy(&peer->sessions, NULL);
  177. if(peer->sobj) {
  178. DEBUGASSERT(peer->sobj_free);
  179. if(peer->sobj_free)
  180. peer->sobj_free(peer->sobj);
  181. peer->sobj = NULL;
  182. }
  183. peer->sobj_free = NULL;
  184. Curl_safefree(peer->clientcert);
  185. #ifdef USE_TLS_SRP
  186. Curl_safefree(peer->srp_username);
  187. Curl_safefree(peer->srp_password);
  188. #endif
  189. Curl_safefree(peer->ssl_peer_key);
  190. peer->age = 0;
  191. peer->hmac_set = FALSE;
  192. }
  193. static void cf_ssl_scache_peer_set_obj(struct Curl_ssl_scache_peer *peer,
  194. void *sobj,
  195. Curl_ssl_scache_obj_dtor *sobj_free)
  196. {
  197. DEBUGASSERT(peer);
  198. if(peer->sobj_free) {
  199. peer->sobj_free(peer->sobj);
  200. }
  201. peer->sobj = sobj;
  202. peer->sobj_free = sobj_free;
  203. }
  204. static CURLcode cf_ssl_scache_peer_init(struct Curl_ssl_scache_peer *peer,
  205. const char *ssl_peer_key,
  206. const char *clientcert,
  207. const char *srp_username,
  208. const char *srp_password)
  209. {
  210. CURLcode result = CURLE_OUT_OF_MEMORY;
  211. DEBUGASSERT(!peer->ssl_peer_key);
  212. peer->ssl_peer_key = strdup(ssl_peer_key);
  213. if(!peer->ssl_peer_key)
  214. goto out;
  215. if(clientcert) {
  216. peer->clientcert = strdup(clientcert);
  217. if(!peer->clientcert)
  218. goto out;
  219. }
  220. if(srp_username) {
  221. peer->srp_username = strdup(srp_username);
  222. if(!peer->srp_username)
  223. goto out;
  224. }
  225. if(srp_password) {
  226. peer->srp_password = strdup(srp_password);
  227. if(!peer->srp_password)
  228. goto out;
  229. }
  230. result = CURLE_OK;
  231. out:
  232. if(result)
  233. cf_ssl_scache_clear_peer(peer);
  234. return result;
  235. }
  236. static void cf_scache_session_remove(struct Curl_ssl_scache_peer *peer,
  237. struct Curl_ssl_session *s)
  238. {
  239. (void)peer;
  240. DEBUGASSERT(Curl_node_llist(&s->list) == &peer->sessions);
  241. Curl_ssl_session_destroy(s);
  242. }
  243. static bool cf_scache_session_expired(struct Curl_ssl_session *s,
  244. curl_off_t now)
  245. {
  246. return (s->lifetime_secs > 0 &&
  247. (s->time_received + s->lifetime_secs) < now);
  248. }
  249. static void cf_scache_peer_remove_expired(struct Curl_ssl_scache_peer *peer,
  250. curl_off_t now)
  251. {
  252. struct Curl_llist_node *n = Curl_llist_head(&peer->sessions);
  253. while(n) {
  254. struct Curl_ssl_session *s = Curl_node_elem(n);
  255. n = Curl_node_next(n);
  256. if(cf_scache_session_expired(s, now))
  257. cf_scache_session_remove(peer, s);
  258. }
  259. }
  260. static void cf_scache_peer_remove_non13(struct Curl_ssl_scache_peer *peer)
  261. {
  262. struct Curl_llist_node *n = Curl_llist_head(&peer->sessions);
  263. while(n) {
  264. struct Curl_ssl_session *s = Curl_node_elem(n);
  265. n = Curl_node_next(n);
  266. if(s->ietf_tls_id != CURL_IETF_PROTO_TLS1_3)
  267. cf_scache_session_remove(peer, s);
  268. }
  269. }
  270. CURLcode Curl_ssl_scache_create(size_t max_peers,
  271. size_t max_sessions_per_peer,
  272. struct Curl_ssl_scache **pscache)
  273. {
  274. struct Curl_ssl_scache *scache;
  275. struct Curl_ssl_scache_peer *peers;
  276. size_t i;
  277. *pscache = NULL;
  278. peers = calloc(max_peers, sizeof(*peers));
  279. if(!peers)
  280. return CURLE_OUT_OF_MEMORY;
  281. scache = calloc(1, sizeof(*scache));
  282. if(!scache) {
  283. free(peers);
  284. return CURLE_OUT_OF_MEMORY;
  285. }
  286. scache->default_lifetime_secs = (24*60*60); /* 1 day */
  287. scache->peer_count = max_peers;
  288. scache->peers = peers;
  289. scache->age = 1;
  290. for(i = 0; i < scache->peer_count; ++i) {
  291. scache->peers[i].max_sessions = max_sessions_per_peer;
  292. Curl_llist_init(&scache->peers[i].sessions,
  293. cf_ssl_scache_sesssion_ldestroy);
  294. }
  295. *pscache = scache;
  296. return CURLE_OK;
  297. }
  298. void Curl_ssl_scache_destroy(struct Curl_ssl_scache *scache)
  299. {
  300. if(scache) {
  301. size_t i;
  302. for(i = 0; i < scache->peer_count; ++i) {
  303. cf_ssl_scache_clear_peer(&scache->peers[i]);
  304. }
  305. free(scache->peers);
  306. free(scache);
  307. }
  308. }
  309. /* Lock shared SSL session data */
  310. void Curl_ssl_scache_lock(struct Curl_easy *data)
  311. {
  312. if(CURL_SHARE_ssl_scache(data))
  313. Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
  314. }
  315. /* Unlock shared SSL session data */
  316. void Curl_ssl_scache_unlock(struct Curl_easy *data)
  317. {
  318. if(CURL_SHARE_ssl_scache(data))
  319. Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
  320. }
  321. static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
  322. const char *name,
  323. char *path)
  324. {
  325. if(path && path[0]) {
  326. /* We try to add absolute paths, so that the session key can stay
  327. * valid when used in another process with different CWD. However,
  328. * when a path does not exist, this does not work. Then, we add
  329. * the path as is. */
  330. #ifdef _WIN32
  331. char abspath[_MAX_PATH];
  332. if(_fullpath(abspath, path, _MAX_PATH))
  333. return Curl_dyn_addf(buf, ":%s-%s", name, abspath);
  334. #else
  335. if(path[0] != '/') {
  336. char *abspath = realpath(path, NULL);
  337. if(abspath) {
  338. CURLcode r = Curl_dyn_addf(buf, ":%s-%s", name, abspath);
  339. (free)(abspath); /* allocated by libc, free without memdebug */
  340. return r;
  341. }
  342. }
  343. #endif
  344. return Curl_dyn_addf(buf, ":%s-%s", name, path);
  345. }
  346. return CURLE_OK;
  347. }
  348. static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf,
  349. const char *name,
  350. struct curl_blob *blob)
  351. {
  352. CURLcode r = CURLE_OK;
  353. if(blob && blob->len) {
  354. unsigned char hash[CURL_SHA256_DIGEST_LENGTH];
  355. size_t i;
  356. r = Curl_dyn_addf(buf, ":%s-", name);
  357. if(r)
  358. goto out;
  359. r = Curl_sha256it(hash, blob->data, blob->len);
  360. if(r)
  361. goto out;
  362. for(i = 0; i < CURL_SHA256_DIGEST_LENGTH; ++i) {
  363. r = Curl_dyn_addf(buf, "%02x", hash[i]);
  364. if(r)
  365. goto out;
  366. }
  367. }
  368. out:
  369. return r;
  370. }
  371. CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
  372. const struct ssl_peer *peer,
  373. const char *tls_id,
  374. char **ppeer_key)
  375. {
  376. struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
  377. struct dynbuf buf;
  378. size_t key_len;
  379. CURLcode r;
  380. *ppeer_key = NULL;
  381. Curl_dyn_init(&buf, 10 * 1024);
  382. r = Curl_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port);
  383. if(r)
  384. goto out;
  385. switch(peer->transport) {
  386. case TRNSPRT_TCP:
  387. break;
  388. case TRNSPRT_UDP:
  389. r = Curl_dyn_add(&buf, ":UDP");
  390. break;
  391. case TRNSPRT_QUIC:
  392. r = Curl_dyn_add(&buf, ":QUIC");
  393. break;
  394. case TRNSPRT_UNIX:
  395. r = Curl_dyn_add(&buf, ":UNIX");
  396. break;
  397. default:
  398. r = Curl_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
  399. break;
  400. }
  401. if(r)
  402. goto out;
  403. if(!ssl->verifypeer) {
  404. r = Curl_dyn_add(&buf, ":NO-VRFY-PEER");
  405. if(r)
  406. goto out;
  407. }
  408. if(!ssl->verifyhost) {
  409. r = Curl_dyn_add(&buf, ":NO-VRFY-HOST");
  410. if(r)
  411. goto out;
  412. }
  413. if(ssl->verifystatus) {
  414. r = Curl_dyn_add(&buf, ":VRFY-STATUS");
  415. if(r)
  416. goto out;
  417. }
  418. if(!ssl->verifypeer || !ssl->verifyhost) {
  419. if(cf->conn->bits.conn_to_host) {
  420. r = Curl_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name);
  421. if(r)
  422. goto out;
  423. }
  424. if(cf->conn->bits.conn_to_port) {
  425. r = Curl_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port);
  426. if(r)
  427. goto out;
  428. }
  429. }
  430. if(ssl->version || ssl->version_max) {
  431. r = Curl_dyn_addf(&buf, ":TLSVER-%d-%d", ssl->version,
  432. (ssl->version_max >> 16));
  433. if(r)
  434. goto out;
  435. }
  436. if(ssl->ssl_options) {
  437. r = Curl_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options);
  438. if(r)
  439. goto out;
  440. }
  441. if(ssl->cipher_list) {
  442. r = Curl_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list);
  443. if(r)
  444. goto out;
  445. }
  446. if(ssl->cipher_list13) {
  447. r = Curl_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13);
  448. if(r)
  449. goto out;
  450. }
  451. if(ssl->curves) {
  452. r = Curl_dyn_addf(&buf, ":CURVES-%s", ssl->curves);
  453. if(r)
  454. goto out;
  455. }
  456. if(ssl->verifypeer) {
  457. r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile);
  458. if(r)
  459. goto out;
  460. r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath);
  461. if(r)
  462. goto out;
  463. r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile);
  464. if(r)
  465. goto out;
  466. r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert);
  467. if(r)
  468. goto out;
  469. if(ssl->cert_blob) {
  470. r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob);
  471. if(r)
  472. goto out;
  473. }
  474. if(ssl->ca_info_blob) {
  475. r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob);
  476. if(r)
  477. goto out;
  478. }
  479. if(ssl->issuercert_blob) {
  480. r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob);
  481. if(r)
  482. goto out;
  483. }
  484. }
  485. if(ssl->pinned_key && ssl->pinned_key[0]) {
  486. r = Curl_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key);
  487. if(r)
  488. goto out;
  489. }
  490. if(ssl->clientcert && ssl->clientcert[0]) {
  491. r = Curl_dyn_add(&buf, ":CCERT");
  492. if(r)
  493. goto out;
  494. }
  495. #ifdef USE_TLS_SRP
  496. if(ssl->username || ssl->password) {
  497. r = Curl_dyn_add(&buf, ":SRP-AUTH");
  498. if(r)
  499. goto out;
  500. }
  501. #endif
  502. if(!tls_id || !tls_id[0]) {
  503. r = CURLE_FAILED_INIT;
  504. goto out;
  505. }
  506. r = Curl_dyn_addf(&buf, ":IMPL-%s", tls_id);
  507. if(r)
  508. goto out;
  509. *ppeer_key = Curl_dyn_take(&buf, &key_len);
  510. /* we just added printable char, and dynbuf always 0 terminates,
  511. * no need to track length */
  512. out:
  513. Curl_dyn_free(&buf);
  514. return r;
  515. }
  516. static bool cf_ssl_scache_match_auth(struct Curl_ssl_scache_peer *peer,
  517. struct ssl_primary_config *conn_config)
  518. {
  519. if(!Curl_safecmp(peer->clientcert, conn_config->clientcert))
  520. return FALSE;
  521. #ifdef USE_TLS_SRP
  522. if(Curl_timestrcmp(peer->srp_username, conn_config->username) ||
  523. Curl_timestrcmp(peer->srp_password, conn_config->password))
  524. return FALSE;
  525. #endif
  526. return TRUE;
  527. }
  528. static CURLcode cf_ssl_find_peer(struct Curl_cfilter *cf,
  529. struct Curl_easy *data,
  530. struct Curl_ssl_scache *scache,
  531. const char *ssl_peer_key,
  532. struct Curl_ssl_scache_peer **ppeer)
  533. {
  534. struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  535. struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  536. size_t i, peer_key_len = 0;
  537. CURLcode result = CURLE_OK;
  538. *ppeer = NULL;
  539. if(!ssl_config || !ssl_config->primary.cache_session)
  540. goto out;
  541. /* check for entries with known peer_key */
  542. for(i = 0; scache && i < scache->peer_count; i++) {
  543. if(scache->peers[i].ssl_peer_key &&
  544. strcasecompare(ssl_peer_key, scache->peers[i].ssl_peer_key) &&
  545. cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) {
  546. /* yes, we have a cached session for this! */
  547. *ppeer = &scache->peers[i];
  548. goto out;
  549. }
  550. }
  551. /* check for entries with HMAC set but no known peer_key */
  552. for(i = 0; scache && i < scache->peer_count; i++) {
  553. if(!scache->peers[i].ssl_peer_key &&
  554. scache->peers[i].hmac_set &&
  555. cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) {
  556. /* possible entry with unknown peer_key, check hmac */
  557. unsigned char my_hmac[CURL_SHA256_DIGEST_LENGTH];
  558. if(!peer_key_len) /* we are lazy */
  559. peer_key_len = strlen(ssl_peer_key);
  560. result = Curl_hmacit(&Curl_HMAC_SHA256,
  561. scache->peers[i].key_salt,
  562. sizeof(scache->peers[i].key_salt),
  563. (const unsigned char *)ssl_peer_key,
  564. peer_key_len,
  565. my_hmac);
  566. if(result)
  567. goto out;
  568. if(!memcmp(scache->peers[i].key_hmac, my_hmac, sizeof(my_hmac))) {
  569. /* remember peer_key for future lookups */
  570. scache->peers[i].ssl_peer_key = strdup(ssl_peer_key);
  571. if(!scache->peers[i].ssl_peer_key) {
  572. result = CURLE_OUT_OF_MEMORY;
  573. goto out;
  574. }
  575. *ppeer = &scache->peers[i];
  576. goto out;
  577. }
  578. }
  579. }
  580. out:
  581. if(result)
  582. CURL_TRC_CF(data, cf, "[SACHE] failure finding scache peer: %d", result);
  583. return result;
  584. }
  585. static CURLcode cf_ssl_add_peer(struct Curl_cfilter *cf,
  586. struct Curl_easy *data,
  587. struct Curl_ssl_scache *scache,
  588. const char *ssl_peer_key,
  589. struct Curl_ssl_scache_peer **ppeer)
  590. {
  591. struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  592. struct Curl_ssl_scache_peer *peer = NULL;
  593. size_t i;
  594. CURLcode result;
  595. *ppeer = NULL;
  596. result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer);
  597. if(result || !scache->peer_count)
  598. return result;
  599. if(peer) {
  600. *ppeer = peer;
  601. return CURLE_OK;
  602. }
  603. /* not there, find empty or oldest peer */
  604. for(i = 0; i < scache->peer_count; ++i) {
  605. /* free peer entry? */
  606. if(!scache->peers[i].ssl_peer_key && !scache->peers[i].hmac_set) {
  607. peer = &scache->peers[i];
  608. break;
  609. }
  610. /* peer without sessions and obj */
  611. if(!scache->peers[i].sobj &&
  612. !Curl_llist_count(&scache->peers[i].sessions)) {
  613. peer = &scache->peers[i];
  614. break;
  615. }
  616. /* remember "oldest" peer */
  617. if(!peer || (scache->peers[i].age < peer->age)) {
  618. peer = &scache->peers[i];
  619. }
  620. }
  621. DEBUGASSERT(peer);
  622. if(!peer)
  623. return CURLE_OK;
  624. /* clear previous peer and reinit */
  625. cf_ssl_scache_clear_peer(peer);
  626. result = cf_ssl_scache_peer_init(peer, ssl_peer_key,
  627. conn_config->clientcert,
  628. #ifdef USE_TLS_SRP
  629. conn_config->username,
  630. conn_config->password);
  631. #else
  632. NULL, NULL);
  633. #endif
  634. if(result)
  635. goto out;
  636. /* all ready */
  637. *ppeer = peer;
  638. result = CURLE_OK;
  639. out:
  640. if(result) {
  641. cf_ssl_scache_clear_peer(peer);
  642. CURL_TRC_CF(data, cf, "[SACHE] failure adding peer: %d", result);
  643. }
  644. return result;
  645. }
  646. static CURLcode cf_scache_peer_add_session(struct Curl_cfilter *cf,
  647. struct Curl_easy *data,
  648. struct Curl_ssl_scache *scache,
  649. const char *ssl_peer_key,
  650. struct Curl_ssl_session *s)
  651. {
  652. struct Curl_ssl_scache_peer *peer = NULL;
  653. CURLcode result = CURLE_OUT_OF_MEMORY;
  654. curl_off_t now = (curl_off_t)time(NULL);
  655. if(!scache || !scache->peer_count) {
  656. Curl_ssl_session_destroy(s);
  657. return CURLE_OK;
  658. }
  659. if(!s->time_received)
  660. s->time_received = now;
  661. if(s->lifetime_secs < 0)
  662. s->lifetime_secs = scache->default_lifetime_secs;
  663. if(cf_scache_session_expired(s, now)) {
  664. CURL_TRC_CF(data, cf, "[SCACHE] add, session already expired");
  665. Curl_ssl_session_destroy(s);
  666. return CURLE_OK;
  667. }
  668. result = cf_ssl_add_peer(cf, data, scache, ssl_peer_key, &peer);
  669. if(result || !peer) {
  670. CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result);
  671. Curl_ssl_session_destroy(s);
  672. goto out;
  673. }
  674. /* A session not from TLSv1.3 replaces all other. */
  675. if(s->ietf_tls_id != CURL_IETF_PROTO_TLS1_3) {
  676. Curl_llist_destroy(&peer->sessions, NULL);
  677. Curl_llist_append(&peer->sessions, s, &s->list);
  678. }
  679. else {
  680. /* Expire existing, append, trim from head to obey max_sessions */
  681. cf_scache_peer_remove_expired(peer, now);
  682. cf_scache_peer_remove_non13(peer);
  683. Curl_llist_append(&peer->sessions, s, &s->list);
  684. while(Curl_llist_count(&peer->sessions) > peer->max_sessions) {
  685. Curl_node_remove(Curl_llist_head(&peer->sessions));
  686. }
  687. }
  688. out:
  689. if(result) {
  690. failf(data, "[SCACHE] failed to add session for %s, error=%d",
  691. ssl_peer_key, result);
  692. }
  693. else
  694. CURL_TRC_CF(data, cf, "[SCACHE] added session for %s [proto=0x%x, "
  695. "lifetime=%d, alpn=%s, earlydata=%zu, quic_tp=%s], "
  696. "peer has %zu sessions now",
  697. ssl_peer_key, s->ietf_tls_id, s->lifetime_secs, s->alpn,
  698. s->earlydata_max, s->quic_tp ? "yes" : "no",
  699. Curl_llist_count(&peer->sessions));
  700. return result;
  701. }
  702. CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf,
  703. struct Curl_easy *data,
  704. const char *ssl_peer_key,
  705. struct Curl_ssl_session *s)
  706. {
  707. struct Curl_ssl_scache *scache = data->state.ssl_scache;
  708. CURLcode result;
  709. Curl_ssl_scache_lock(data);
  710. result = cf_scache_peer_add_session(cf, data, scache, ssl_peer_key, s);
  711. Curl_ssl_scache_unlock(data);
  712. return result;
  713. }
  714. void Curl_ssl_scache_return(struct Curl_cfilter *cf,
  715. struct Curl_easy *data,
  716. const char *ssl_peer_key,
  717. struct Curl_ssl_session *s)
  718. {
  719. /* See RFC 8446 C.4:
  720. * "Clients SHOULD NOT reuse a ticket for multiple connections." */
  721. if(s && s->ietf_tls_id < 0x304)
  722. (void)Curl_ssl_scache_put(cf, data, ssl_peer_key, s);
  723. else
  724. Curl_ssl_session_destroy(s);
  725. }
  726. CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf,
  727. struct Curl_easy *data,
  728. const char *ssl_peer_key,
  729. struct Curl_ssl_session **ps)
  730. {
  731. struct Curl_ssl_scache *scache = data->state.ssl_scache;
  732. struct Curl_ssl_scache_peer *peer = NULL;
  733. struct Curl_llist_node *n;
  734. struct Curl_ssl_session *s = NULL;
  735. CURLcode result;
  736. *ps = NULL;
  737. if(!scache)
  738. return CURLE_OK;
  739. Curl_ssl_scache_lock(data);
  740. result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer);
  741. if(!result && peer) {
  742. cf_scache_peer_remove_expired(peer, (curl_off_t)time(NULL));
  743. n = Curl_llist_head(&peer->sessions);
  744. if(n) {
  745. s = Curl_node_take_elem(n);
  746. (scache->age)++; /* increase general age */
  747. peer->age = scache->age; /* set this as used in this age */
  748. }
  749. }
  750. Curl_ssl_scache_unlock(data);
  751. if(s) {
  752. *ps = s;
  753. CURL_TRC_CF(data, cf, "[SCACHE] took session for %s [proto=0x%x, "
  754. "lifetime=%d, alpn=%s, earlydata=%zu, quic_tp=%s], "
  755. "%zu sessions remain",
  756. ssl_peer_key, s->ietf_tls_id, s->lifetime_secs, s->alpn,
  757. s->earlydata_max, s->quic_tp ? "yes" : "no",
  758. Curl_llist_count(&peer->sessions));
  759. }
  760. else {
  761. CURL_TRC_CF(data, cf, "[SCACHE] no cached session for %s", ssl_peer_key);
  762. }
  763. return result;
  764. }
  765. CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf,
  766. struct Curl_easy *data,
  767. const char *ssl_peer_key,
  768. void *sobj,
  769. Curl_ssl_scache_obj_dtor *sobj_free)
  770. {
  771. struct Curl_ssl_scache *scache = data->state.ssl_scache;
  772. struct Curl_ssl_scache_peer *peer = NULL;
  773. CURLcode result;
  774. DEBUGASSERT(sobj);
  775. DEBUGASSERT(sobj_free);
  776. result = cf_ssl_add_peer(cf, data, scache, ssl_peer_key, &peer);
  777. if(result || !peer) {
  778. CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result);
  779. goto out;
  780. }
  781. cf_ssl_scache_peer_set_obj(peer, sobj, sobj_free);
  782. sobj = NULL; /* peer took ownership */
  783. out:
  784. if(sobj && sobj_free)
  785. sobj_free(sobj);
  786. return result;
  787. }
  788. bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf,
  789. struct Curl_easy *data,
  790. const char *ssl_peer_key,
  791. void **sobj)
  792. {
  793. struct Curl_ssl_scache *scache = data->state.ssl_scache;
  794. struct Curl_ssl_scache_peer *peer = NULL;
  795. CURLcode result;
  796. *sobj = NULL;
  797. if(!scache)
  798. return FALSE;
  799. result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer);
  800. if(result)
  801. return FALSE;
  802. if(peer)
  803. *sobj = peer->sobj;
  804. CURL_TRC_CF(data, cf, "[SACHE] %s cached session for '%s'",
  805. *sobj ? "Found" : "No", ssl_peer_key);
  806. return !!*sobj;
  807. }
  808. void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf,
  809. struct Curl_easy *data,
  810. const char *ssl_peer_key)
  811. {
  812. struct Curl_ssl_scache *scache = data->state.ssl_scache;
  813. struct Curl_ssl_scache_peer *peer = NULL;
  814. CURLcode result;
  815. (void)cf;
  816. if(!scache)
  817. return;
  818. Curl_ssl_scache_lock(data);
  819. result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer);
  820. if(!result && peer)
  821. cf_ssl_scache_clear_peer(peer);
  822. Curl_ssl_scache_unlock(data);
  823. }
  824. #endif /* USE_SSL */