protocol_lws_acme_client.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646
  1. /*
  2. * libwebsockets ACME client protocol plugin
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. *
  24. * Acme is in a big messy transition at the moment from a homebrewed api
  25. * to an IETF one. The old repo for the homebrew api (they currently
  26. * implement) is marked up as deprecated and "not accurate[ly] reflect[ing]"
  27. * what they implement, but the IETF standard, currently at v7 is not yet
  28. * implemented at let's encrypt (ETA Jan 2018).
  29. *
  30. * This implementation follows draft 7 of the IETF standard, and falls back
  31. * to whatever differences exist for Boulder's tls-sni-01 challenge. The
  32. * tls-sni-02 support is there but nothing to test it against at the time of
  33. * writing (Nov 1 2017).
  34. */
  35. #if !defined (LWS_PLUGIN_STATIC)
  36. #define LWS_DLL
  37. #define LWS_INTERNAL
  38. #include <libwebsockets.h>
  39. #endif
  40. #include <string.h>
  41. #include <stdlib.h>
  42. typedef enum {
  43. ACME_STATE_DIRECTORY, /* get the directory JSON using GET + parse */
  44. ACME_STATE_NEW_NONCE, /* get the replay nonce */
  45. ACME_STATE_NEW_ACCOUNT, /* register a new RSA key + email combo */
  46. ACME_STATE_NEW_ORDER, /* start the process to request a cert */
  47. ACME_STATE_AUTHZ, /* */
  48. ACME_STATE_START_CHALL, /* notify server ready for one challenge */
  49. ACME_STATE_POLLING, /* he should be trying our challenge */
  50. ACME_STATE_POLLING_CSR, /* sent CSR, checking result */
  51. ACME_STATE_DOWNLOAD_CERT,
  52. ACME_STATE_FINISHED
  53. } lws_acme_state;
  54. struct acme_connection {
  55. char buf[4096];
  56. char replay_nonce[64];
  57. char chall_token[64];
  58. char challenge_uri[256];
  59. char detail[64];
  60. char status[16];
  61. char key_auth[256];
  62. char http01_mountpoint[256];
  63. struct lws_http_mount mount;
  64. char urls[6][100]; /* directory contents */
  65. char active_url[100];
  66. char authz_url[100];
  67. char order_url[100];
  68. char finalize_url[100];
  69. char cert_url[100];
  70. char acct_id[100];
  71. char *kid;
  72. lws_acme_state state;
  73. struct lws_client_connect_info i;
  74. struct lejp_ctx jctx;
  75. struct lws_context_creation_info ci;
  76. struct lws_vhost *vhost;
  77. struct lws *cwsi;
  78. const char *real_vh_name;
  79. const char *real_vh_iface;
  80. char *alloc_privkey_pem;
  81. char *dest;
  82. int pos;
  83. int len;
  84. int resp;
  85. int cpos;
  86. int real_vh_port;
  87. int goes_around;
  88. size_t len_privkey_pem;
  89. unsigned int yes:2;
  90. unsigned int use:1;
  91. unsigned int is_sni_02:1;
  92. };
  93. struct per_vhost_data__lws_acme_client {
  94. struct lws_context *context;
  95. struct lws_vhost *vhost;
  96. const struct lws_protocols *protocol;
  97. /*
  98. * the vhd is allocated for every vhost using the plugin.
  99. * But ac is only allocated when we are doing the server auth.
  100. */
  101. struct acme_connection *ac;
  102. struct lws_jwk jwk;
  103. struct lws_genrsa_ctx rsactx;
  104. char *pvo_data;
  105. char *pvop[LWS_TLS_TOTAL_COUNT];
  106. const char *pvop_active[LWS_TLS_TOTAL_COUNT];
  107. int count_live_pss;
  108. char *dest;
  109. int pos;
  110. int len;
  111. int fd_updated_cert; /* these are opened while we have root... */
  112. int fd_updated_key; /* ...if nonempty next startup will replace old */
  113. };
  114. static int
  115. callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason,
  116. void *user, void *in, size_t len)
  117. {
  118. struct lws_vhost *vhost = lws_get_vhost(wsi);
  119. struct acme_connection *ac = lws_vhost_user(vhost);
  120. uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
  121. *end = &buf[sizeof(buf) - LWS_PRE - 1];
  122. int n;
  123. switch (reason) {
  124. case LWS_CALLBACK_HTTP:
  125. lwsl_notice("%s: ca connection received, key_auth %s\n",
  126. __func__, ac->key_auth);
  127. if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) {
  128. lwsl_notice("%s: add status failed\n", __func__);
  129. return -1;
  130. }
  131. if (lws_add_http_header_by_token(wsi,
  132. WSI_TOKEN_HTTP_CONTENT_TYPE,
  133. (unsigned char *)"text/plain", 10,
  134. &p, end)) {
  135. lwsl_notice("%s: add content_type failed\n", __func__);
  136. return -1;
  137. }
  138. n = strlen(ac->key_auth);
  139. if (lws_add_http_header_content_length(wsi, n, &p, end)) {
  140. lwsl_notice("%s: add content_length failed\n",
  141. __func__);
  142. return -1;
  143. }
  144. if (lws_add_http_header_by_token(wsi,
  145. WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
  146. (unsigned char *)"attachment", 10,
  147. &p, end)) {
  148. lwsl_notice("%s: add content_dispo failed\n", __func__);
  149. return -1;
  150. }
  151. if (lws_finalize_write_http_header(wsi, start, &p, end)) {
  152. lwsl_notice("%s: finalize http header failed\n",
  153. __func__);
  154. return -1;
  155. }
  156. lws_callback_on_writable(wsi);
  157. return 0;
  158. case LWS_CALLBACK_HTTP_WRITEABLE:
  159. p += lws_snprintf((char *)p, end - p, "%s", ac->key_auth);
  160. lwsl_notice("%s: len %d\n", __func__, lws_ptr_diff(p, start));
  161. if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start),
  162. LWS_WRITE_HTTP_FINAL) != lws_ptr_diff(p, start)) {
  163. lwsl_err("_write content failed\n");
  164. return 1;
  165. }
  166. if (lws_http_transaction_completed(wsi))
  167. return -1;
  168. return 0;
  169. default:
  170. break;
  171. }
  172. return lws_callback_http_dummy(wsi, reason, user, in, len);
  173. }
  174. static const struct lws_protocols chall_http01_protocols[] = {
  175. { "http", callback_chall_http01, 0, 0, 0, NULL, 0 },
  176. { NULL, NULL, 0, 0, 0, NULL, 0 }
  177. };
  178. static int
  179. jws_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
  180. const char *nonce, const char *url, const char *kid,
  181. char *out, size_t out_len, struct lws_context *context)
  182. {
  183. char *buf, *start, *p, *end, *p1, *end1;
  184. struct lws_jws jws;
  185. int n, m;
  186. lws_jws_init(&jws, &jwe->jwk, context);
  187. /*
  188. * This buffer is local to the function, the actual output is prepared
  189. * into out. Only the plaintext protected header
  190. * (which contains the public key, 512 bytes for 4096b) goes in
  191. * here temporarily.
  192. */
  193. n = LWS_PRE + 2048;
  194. buf = malloc(n);
  195. if (!buf) {
  196. lwsl_notice("%s: malloc %d failed\n", __func__, n);
  197. return -1;
  198. }
  199. p = start = buf + LWS_PRE;
  200. end = buf + n - LWS_PRE - 1;
  201. /*
  202. * temporary JWS protected header plaintext
  203. */
  204. if (!jwe->jose.alg || !jwe->jose.alg->alg)
  205. goto bail;
  206. p += lws_snprintf(p, end - p, "{\"alg\":\"RS256\"");
  207. if (kid)
  208. p += lws_snprintf(p, end - p, ",\"kid\":\"%s\"", kid);
  209. else {
  210. p += lws_snprintf(p, end - p, ",\"jwk\":");
  211. m = end - p;
  212. n = lws_jwk_export(&jwe->jwk, 0, p, &m);
  213. if (n < 0) {
  214. lwsl_notice("failed to export jwk\n");
  215. goto bail;
  216. }
  217. p += n;
  218. }
  219. p += lws_snprintf(p, end - p, ",\"url\":\"%s\"", url);
  220. p += lws_snprintf(p, end - p, ",\"nonce\":\"%s\"}", nonce);
  221. /*
  222. * prepare the signed outer JSON with all the parts in
  223. */
  224. p1 = out;
  225. end1 = out + out_len - 1;
  226. p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\"");
  227. jws.map_b64.buf[LJWS_JOSE] = p1;
  228. n = lws_jws_base64_enc(start, p - start, p1, end1 - p1);
  229. if (n < 0) {
  230. lwsl_notice("%s: failed to encode protected\n", __func__);
  231. goto bail;
  232. }
  233. jws.map_b64.len[LJWS_JOSE] = n;
  234. p1 += n;
  235. p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\"");
  236. jws.map_b64.buf[LJWS_PYLD] = p1;
  237. n = lws_jws_base64_enc(payload, len, p1, end1 - p1);
  238. if (n < 0) {
  239. lwsl_notice("%s: failed to encode payload\n", __func__);
  240. goto bail;
  241. }
  242. jws.map_b64.len[LJWS_PYLD] = n;
  243. p1 += n;
  244. p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\"");
  245. /*
  246. * taking the b64 protected header and the b64 payload, sign them
  247. * and place the signature into the packet
  248. */
  249. n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, end1 - p1);
  250. if (n < 0) {
  251. lwsl_notice("sig gen failed\n");
  252. goto bail;
  253. }
  254. jws.map_b64.buf[LJWS_SIG] = p1;
  255. jws.map_b64.len[LJWS_SIG] = n;
  256. p1 += n;
  257. p1 += lws_snprintf(p1, end1 - p1, "\"}");
  258. free(buf);
  259. return p1 - out;
  260. bail:
  261. lws_jws_destroy(&jws);
  262. free(buf);
  263. return -1;
  264. }
  265. static int
  266. callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
  267. void *user, void *in, size_t len);
  268. #define LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT \
  269. { \
  270. "lws-acme-client", \
  271. callback_acme_client, \
  272. 0, \
  273. 512, \
  274. 0, NULL, 0 \
  275. }
  276. /* directory JSON parsing */
  277. static const char * const jdir_tok[] = {
  278. "keyChange",
  279. "meta.termsOfService",
  280. "newAccount",
  281. "newNonce",
  282. "newOrder",
  283. "revokeCert",
  284. };
  285. enum enum_jdir_tok {
  286. JAD_KEY_CHANGE_URL,
  287. JAD_TOS_URL,
  288. JAD_NEW_ACCOUNT_URL,
  289. JAD_NEW_NONCE_URL,
  290. JAD_NEW_ORDER_URL,
  291. JAD_REVOKE_CERT_URL,
  292. };
  293. static signed char
  294. cb_dir(struct lejp_ctx *ctx, char reason)
  295. {
  296. struct per_vhost_data__lws_acme_client *s =
  297. (struct per_vhost_data__lws_acme_client *)ctx->user;
  298. if (reason == LEJPCB_VAL_STR_START && ctx->path_match) {
  299. s->pos = 0;
  300. s->len = sizeof(s->ac->urls[0]) - 1;
  301. s->dest = s->ac->urls[ctx->path_match - 1];
  302. return 0;
  303. }
  304. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  305. return 0;
  306. if (s->pos + ctx->npos > s->len) {
  307. lwsl_notice("url too long\n");
  308. return -1;
  309. }
  310. memcpy(s->dest + s->pos, ctx->buf, ctx->npos);
  311. s->pos += ctx->npos;
  312. s->dest[s->pos] = '\0';
  313. return 0;
  314. }
  315. /* order JSON parsing */
  316. static const char * const jorder_tok[] = {
  317. "status",
  318. "expires",
  319. "identifiers[].type",
  320. "identifiers[].value",
  321. "authorizations",
  322. "finalize",
  323. "certificate"
  324. };
  325. enum enum_jorder_tok {
  326. JAO_STATUS,
  327. JAO_EXPIRES,
  328. JAO_IDENTIFIERS_TYPE,
  329. JAO_IDENTIFIERS_VALUE,
  330. JAO_AUTHORIZATIONS,
  331. JAO_FINALIZE,
  332. JAO_CERT
  333. };
  334. static signed char
  335. cb_order(struct lejp_ctx *ctx, char reason)
  336. {
  337. struct acme_connection *s = (struct acme_connection *)ctx->user;
  338. if (reason == LEJPCB_CONSTRUCTED)
  339. s->authz_url[0] = '\0';
  340. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  341. return 0;
  342. switch (ctx->path_match - 1) {
  343. case JAO_STATUS:
  344. lws_strncpy(s->status, ctx->buf, sizeof(s->status));
  345. break;
  346. case JAO_EXPIRES:
  347. break;
  348. case JAO_IDENTIFIERS_TYPE:
  349. break;
  350. case JAO_IDENTIFIERS_VALUE:
  351. break;
  352. case JAO_AUTHORIZATIONS:
  353. lws_snprintf(s->authz_url, sizeof(s->authz_url), "%s",
  354. ctx->buf);
  355. break;
  356. case JAO_FINALIZE:
  357. lws_snprintf(s->finalize_url, sizeof(s->finalize_url), "%s",
  358. ctx->buf);
  359. break;
  360. case JAO_CERT:
  361. lws_snprintf(s->cert_url, sizeof(s->cert_url), "%s", ctx->buf);
  362. break;
  363. }
  364. return 0;
  365. }
  366. /* authz JSON parsing */
  367. static const char * const jauthz_tok[] = {
  368. "identifier.type",
  369. "identifier.value",
  370. "status",
  371. "expires",
  372. "challenges[].type",
  373. "challenges[].status",
  374. "challenges[].url",
  375. "challenges[].token",
  376. "detail"
  377. };
  378. enum enum_jauthz_tok {
  379. JAAZ_ID_TYPE,
  380. JAAZ_ID_VALUE,
  381. JAAZ_STATUS,
  382. JAAZ_EXPIRES,
  383. JAAZ_CHALLENGES_TYPE,
  384. JAAZ_CHALLENGES_STATUS,
  385. JAAZ_CHALLENGES_URL,
  386. JAAZ_CHALLENGES_TOKEN,
  387. JAAZ_DETAIL,
  388. };
  389. static signed char
  390. cb_authz(struct lejp_ctx *ctx, char reason)
  391. {
  392. struct acme_connection *s = (struct acme_connection *)ctx->user;
  393. if (reason == LEJPCB_CONSTRUCTED) {
  394. s->yes = 0;
  395. s->use = 0;
  396. s->chall_token[0] = '\0';
  397. }
  398. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  399. return 0;
  400. switch (ctx->path_match - 1) {
  401. case JAAZ_ID_TYPE:
  402. break;
  403. case JAAZ_ID_VALUE:
  404. break;
  405. case JAAZ_STATUS:
  406. break;
  407. case JAAZ_EXPIRES:
  408. break;
  409. case JAAZ_DETAIL:
  410. lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
  411. break;
  412. case JAAZ_CHALLENGES_TYPE:
  413. lwsl_notice("JAAZ_CHALLENGES_TYPE: %s\n", ctx->buf);
  414. s->use = !strcmp(ctx->buf, "http-01");
  415. break;
  416. case JAAZ_CHALLENGES_STATUS:
  417. lws_strncpy(s->status, ctx->buf, sizeof(s->status));
  418. break;
  419. case JAAZ_CHALLENGES_URL:
  420. lwsl_notice("JAAZ_CHALLENGES_URL: %s %d\n", ctx->buf, s->use);
  421. if (s->use) {
  422. lws_strncpy(s->challenge_uri, ctx->buf,
  423. sizeof(s->challenge_uri));
  424. s->yes |= 2;
  425. }
  426. break;
  427. case JAAZ_CHALLENGES_TOKEN:
  428. lwsl_notice("JAAZ_CHALLENGES_TOKEN: %s %d\n", ctx->buf, s->use);
  429. if (s->use) {
  430. lws_strncpy(s->chall_token, ctx->buf,
  431. sizeof(s->chall_token));
  432. s->yes |= 1;
  433. }
  434. break;
  435. }
  436. return 0;
  437. }
  438. /* challenge accepted JSON parsing */
  439. static const char * const jchac_tok[] = {
  440. "type",
  441. "status",
  442. "uri",
  443. "token",
  444. "error.detail"
  445. };
  446. enum enum_jchac_tok {
  447. JCAC_TYPE,
  448. JCAC_STATUS,
  449. JCAC_URI,
  450. JCAC_TOKEN,
  451. JCAC_DETAIL,
  452. };
  453. static signed char
  454. cb_chac(struct lejp_ctx *ctx, char reason)
  455. {
  456. struct acme_connection *s = (struct acme_connection *)ctx->user;
  457. if (reason == LEJPCB_CONSTRUCTED) {
  458. s->yes = 0;
  459. s->use = 0;
  460. }
  461. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  462. return 0;
  463. switch (ctx->path_match - 1) {
  464. case JCAC_TYPE:
  465. if (strcmp(ctx->buf, "http-01"))
  466. return 1;
  467. break;
  468. case JCAC_STATUS:
  469. lws_strncpy(s->status, ctx->buf, sizeof(s->status));
  470. break;
  471. case JCAC_URI:
  472. s->yes |= 2;
  473. break;
  474. case JCAC_TOKEN:
  475. lws_strncpy(s->chall_token, ctx->buf, sizeof(s->chall_token));
  476. s->yes |= 1;
  477. break;
  478. case JCAC_DETAIL:
  479. lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
  480. break;
  481. }
  482. return 0;
  483. }
  484. static int
  485. lws_acme_report_status(struct lws_vhost *v, int state, const char *json)
  486. {
  487. lws_callback_vhost_protocols_vhost(v, LWS_CALLBACK_VHOST_CERT_UPDATE,
  488. (void *)json, state);
  489. return 0;
  490. }
  491. /*
  492. * Notice: trashes i and url
  493. */
  494. static struct lws *
  495. lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
  496. struct lws **pwsi, struct lws_client_connect_info *i,
  497. char *url, const char *method)
  498. {
  499. const char *prot, *p;
  500. char path[200], _url[256];
  501. struct lws *wsi;
  502. memset(i, 0, sizeof(*i));
  503. i->port = 443;
  504. lws_strncpy(_url, url, sizeof(_url));
  505. if (lws_parse_uri(_url, &prot, &i->address, &i->port, &p)) {
  506. lwsl_err("unable to parse uri %s\n", url);
  507. return NULL;
  508. }
  509. /* add back the leading / on path */
  510. path[0] = '/';
  511. lws_strncpy(path + 1, p, sizeof(path) - 1);
  512. i->path = path;
  513. i->context = context;
  514. i->vhost = vh;
  515. i->ssl_connection = LCCSCF_USE_SSL;
  516. i->host = i->address;
  517. i->origin = i->address;
  518. i->method = method;
  519. i->pwsi = pwsi;
  520. i->protocol = "lws-acme-client";
  521. wsi = lws_client_connect_via_info(i);
  522. if (!wsi) {
  523. lws_snprintf(path, sizeof(path) - 1,
  524. "Unable to connect to %s", url);
  525. lwsl_notice("%s: %s\n", __func__, path);
  526. lws_acme_report_status(vh, LWS_CUS_FAILED, path);
  527. }
  528. return wsi;
  529. }
  530. static void
  531. lws_acme_finished(struct per_vhost_data__lws_acme_client *vhd)
  532. {
  533. lwsl_notice("%s\n", __func__);
  534. if (vhd->ac) {
  535. if (vhd->ac->vhost)
  536. lws_vhost_destroy(vhd->ac->vhost);
  537. if (vhd->ac->alloc_privkey_pem)
  538. free(vhd->ac->alloc_privkey_pem);
  539. free(vhd->ac);
  540. }
  541. lws_genrsa_destroy(&vhd->rsactx);
  542. lws_jwk_destroy(&vhd->jwk);
  543. vhd->ac = NULL;
  544. #if defined(LWS_WITH_ESP32)
  545. lws_esp32.acme = 0; /* enable scanning */
  546. #endif
  547. }
  548. static const char * const pvo_names[] = {
  549. "country",
  550. "state",
  551. "locality",
  552. "organization",
  553. "common-name",
  554. "subject-alt-name",
  555. "email",
  556. "directory-url",
  557. "auth-path",
  558. "cert-path",
  559. "key-path",
  560. };
  561. static int
  562. lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,
  563. int bits)
  564. {
  565. int n;
  566. if (!lws_jwk_load(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH],
  567. NULL, NULL))
  568. return 0;
  569. vhd->jwk.kty = LWS_GENCRYPTO_KTY_RSA;
  570. lwsl_notice("Generating ACME %d-bit keypair... "
  571. "will take a little while\n", bits);
  572. n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, LGRSAM_PKCS1_1_5,
  573. vhd->jwk.e, bits);
  574. if (n) {
  575. lwsl_notice("failed to create keypair\n");
  576. return 1;
  577. }
  578. lwsl_notice("...keypair generated\n");
  579. if (lws_jwk_save(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
  580. lwsl_notice("unable to save %s\n",
  581. vhd->pvop[LWS_TLS_SET_AUTH_PATH]);
  582. return 1;
  583. }
  584. return 0;
  585. }
  586. static int
  587. lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
  588. struct lws_vhost *v)
  589. {
  590. char buf[128];
  591. /* ...and we were given enough info to do the update? */
  592. if (!vhd->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME])
  593. return -1;
  594. /*
  595. * ...well... we should try to do something about it then...
  596. */
  597. lwsl_notice("%s: ACME cert needs creating / updating: "
  598. "vhost %s\n", __func__, lws_get_vhost_name(vhd->vhost));
  599. vhd->ac = malloc(sizeof(*vhd->ac));
  600. memset(vhd->ac, 0, sizeof(*vhd->ac));
  601. /*
  602. * So if we don't have it, the first job is get the directory.
  603. *
  604. * If we already have the directory, jump straight into trying
  605. * to register our key.
  606. *
  607. * We always try to register the keys... if it's not the first
  608. * time, we will get a JSON body in the (legal, nonfatal)
  609. * response like this
  610. *
  611. * {
  612. * "type": "urn:acme:error:malformed",
  613. * "detail": "Registration key is already in use",
  614. * "status": 409
  615. * }
  616. */
  617. if (!vhd->ac->urls[0][0]) {
  618. vhd->ac->state = ACME_STATE_DIRECTORY;
  619. lws_snprintf(buf, sizeof(buf) - 1, "%s",
  620. vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
  621. } else {
  622. vhd->ac->state = ACME_STATE_NEW_ACCOUNT;
  623. lws_snprintf(buf, sizeof(buf) - 1, "%s",
  624. vhd->ac->urls[JAD_NEW_ACCOUNT_URL]);
  625. }
  626. vhd->ac->real_vh_port = lws_get_vhost_port(vhd->vhost);
  627. vhd->ac->real_vh_name = lws_get_vhost_name(vhd->vhost);
  628. vhd->ac->real_vh_iface = lws_get_vhost_iface(vhd->vhost);
  629. lws_acme_report_status(vhd->vhost, LWS_CUS_STARTING, NULL);
  630. #if defined(LWS_WITH_ESP32)
  631. lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
  632. "Generating keys, please wait");
  633. if (lws_acme_load_create_auth_keys(vhd, 2048))
  634. goto bail;
  635. lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
  636. "Auth keys created");
  637. #endif
  638. if (lws_acme_client_connect(vhd->context, vhd->vhost,
  639. &vhd->ac->cwsi, &vhd->ac->i, buf, "GET"))
  640. return 0;
  641. #if defined(LWS_WITH_ESP32)
  642. bail:
  643. #endif
  644. free(vhd->ac);
  645. vhd->ac = NULL;
  646. return 1;
  647. }
  648. static int
  649. callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
  650. void *user, void *in, size_t len)
  651. {
  652. struct per_vhost_data__lws_acme_client *vhd =
  653. (struct per_vhost_data__lws_acme_client *)
  654. lws_protocol_vh_priv_get(lws_get_vhost(wsi),
  655. lws_get_protocol(wsi));
  656. char buf[LWS_PRE + 2536], *start = buf + LWS_PRE, *p = start,
  657. *end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL;
  658. const struct lws_protocol_vhost_options *pvo;
  659. struct lws_acme_cert_aging_args *caa;
  660. struct acme_connection *ac = NULL;
  661. unsigned char **pp, *pend;
  662. const char *content_type;
  663. struct lws_jwe jwe;
  664. struct lws *cwsi;
  665. int n, m;
  666. if (vhd)
  667. ac = vhd->ac;
  668. lws_jwe_init(&jwe, lws_get_context(wsi));
  669. switch ((int)reason) {
  670. case LWS_CALLBACK_PROTOCOL_INIT:
  671. vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
  672. lws_get_protocol(wsi),
  673. sizeof(struct per_vhost_data__lws_acme_client));
  674. vhd->context = lws_get_context(wsi);
  675. vhd->protocol = lws_get_protocol(wsi);
  676. vhd->vhost = lws_get_vhost(wsi);
  677. /* compute how much we need to hold all the pvo payloads */
  678. m = 0;
  679. pvo = (const struct lws_protocol_vhost_options *)in;
  680. while (pvo) {
  681. m += strlen(pvo->value) + 1;
  682. pvo = pvo->next;
  683. }
  684. p = vhd->pvo_data = malloc(m);
  685. if (!p)
  686. return -1;
  687. pvo = (const struct lws_protocol_vhost_options *)in;
  688. while (pvo) {
  689. start = p;
  690. n = strlen(pvo->value) + 1;
  691. memcpy(start, pvo->value, n);
  692. p += n;
  693. for (m = 0; m < (int)LWS_ARRAY_SIZE(pvo_names); m++)
  694. if (!strcmp(pvo->name, pvo_names[m]))
  695. vhd->pvop[m] = start;
  696. pvo = pvo->next;
  697. }
  698. n = 0;
  699. for (m = 0; m < (int)LWS_ARRAY_SIZE(pvo_names); m++) {
  700. if (!vhd->pvop[m] &&
  701. m >= LWS_TLS_REQ_ELEMENT_COMMON_NAME &&
  702. m != LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME) {
  703. lwsl_notice("%s: require pvo '%s'\n", __func__,
  704. pvo_names[m]);
  705. n |= 1;
  706. } else {
  707. if (vhd->pvop[m])
  708. lwsl_info(" %s: %s\n", pvo_names[m],
  709. vhd->pvop[m]);
  710. }
  711. }
  712. if (n) {
  713. free(vhd->pvo_data);
  714. vhd->pvo_data = NULL;
  715. return -1;
  716. }
  717. #if !defined(LWS_WITH_ESP32)
  718. /*
  719. * load (or create) the registration keypair while we
  720. * still have root
  721. */
  722. if (lws_acme_load_create_auth_keys(vhd, 4096))
  723. return 1;
  724. /*
  725. * in case we do an update, open the update files while we
  726. * still have root
  727. */
  728. lws_snprintf(buf, sizeof(buf) - 1, "%s.upd",
  729. vhd->pvop[LWS_TLS_SET_CERT_PATH]);
  730. vhd->fd_updated_cert = lws_open(buf,
  731. LWS_O_WRONLY | LWS_O_CREAT |
  732. LWS_O_TRUNC, 0600);
  733. if (vhd->fd_updated_cert < 0) {
  734. lwsl_err("unable to create update cert file %s\n", buf);
  735. return -1;
  736. }
  737. lws_snprintf(buf, sizeof(buf) - 1, "%s.upd",
  738. vhd->pvop[LWS_TLS_SET_KEY_PATH]);
  739. vhd->fd_updated_key = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT |
  740. LWS_O_TRUNC, 0600);
  741. if (vhd->fd_updated_key < 0) {
  742. lwsl_err("unable to create update key file %s\n", buf);
  743. return -1;
  744. }
  745. #endif
  746. break;
  747. case LWS_CALLBACK_PROTOCOL_DESTROY:
  748. if (vhd && vhd->pvo_data) {
  749. free(vhd->pvo_data);
  750. vhd->pvo_data = NULL;
  751. }
  752. if (vhd)
  753. lws_acme_finished(vhd);
  754. break;
  755. case LWS_CALLBACK_VHOST_CERT_AGING:
  756. if (!vhd)
  757. break;
  758. caa = (struct lws_acme_cert_aging_args *)in;
  759. /*
  760. * Somebody is telling us about a cert some vhost is using.
  761. *
  762. * First see if the cert is getting close enough to expiry that
  763. * we *want* to do something about it.
  764. */
  765. if ((int)(ssize_t)len > 14)
  766. break;
  767. /*
  768. * ...is this a vhost we were configured on?
  769. */
  770. if (vhd->vhost != caa->vh)
  771. return 1;
  772. for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pvop);n++)
  773. if (caa->element_overrides[n])
  774. vhd->pvop_active[n] = caa->element_overrides[n];
  775. else
  776. vhd->pvop_active[n] = vhd->pvop[n];
  777. lwsl_notice("starting acme acquisition on %s: %s\n",
  778. lws_get_vhost_name(caa->vh),
  779. vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
  780. lws_acme_start_acquisition(vhd, caa->vh);
  781. break;
  782. /*
  783. * Client
  784. */
  785. case LWS_CALLBACK_CLIENT_ESTABLISHED:
  786. lwsl_notice("%s: CLIENT_ESTABLISHED\n", __func__);
  787. break;
  788. case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
  789. lwsl_notice("%s: CLIENT_CONNECTION_ERROR: %p\n", __func__, wsi);
  790. break;
  791. case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
  792. lwsl_notice("%s: CLOSED_CLIENT_HTTP: %p\n", __func__, wsi);
  793. break;
  794. case LWS_CALLBACK_CLOSED:
  795. lwsl_notice("%s: CLOSED: %p\n", __func__, wsi);
  796. break;
  797. case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
  798. lwsl_notice("%s: ESTABLISHED_CLIENT_HTTP:"
  799. "%p, state:%d, status:%d\n", __func__, wsi,
  800. ac->state, lws_http_client_http_response(wsi));
  801. if (!ac)
  802. break;
  803. ac->resp = lws_http_client_http_response(wsi);
  804. /* we get a new nonce each time */
  805. if (lws_hdr_total_length(wsi, WSI_TOKEN_REPLAY_NONCE) &&
  806. lws_hdr_copy(wsi, ac->replay_nonce,
  807. sizeof(ac->replay_nonce),
  808. WSI_TOKEN_REPLAY_NONCE) < 0) {
  809. lwsl_notice("%s: nonce too large\n", __func__);
  810. goto failed;
  811. }
  812. switch (ac->state) {
  813. case ACME_STATE_DIRECTORY:
  814. lejp_construct(&ac->jctx, cb_dir, vhd, jdir_tok,
  815. LWS_ARRAY_SIZE(jdir_tok));
  816. break;
  817. case ACME_STATE_NEW_NONCE:
  818. /*
  819. * we try to * register our keys next.
  820. * It's OK if it ends up * they're already registered,
  821. * this eliminates any * gaps where we stored the key
  822. * but registration did not complete for some reason...
  823. */
  824. ac->state = ACME_STATE_NEW_ACCOUNT;
  825. lws_acme_report_status(vhd->vhost, LWS_CUS_REG, NULL);
  826. strcpy(buf, ac->urls[JAD_NEW_ACCOUNT_URL]);
  827. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  828. &ac->cwsi, &ac->i, buf, "POST");
  829. if (!cwsi) {
  830. lwsl_notice("%s: failed to connect to acme\n",
  831. __func__);
  832. goto failed;
  833. }
  834. return -1;
  835. case ACME_STATE_NEW_ACCOUNT:
  836. if (!lws_hdr_total_length(wsi,
  837. WSI_TOKEN_HTTP_LOCATION)) {
  838. lwsl_notice("%s: no Location\n", __func__);
  839. goto failed;
  840. }
  841. if (lws_hdr_copy(wsi, ac->acct_id, sizeof(ac->acct_id),
  842. WSI_TOKEN_HTTP_LOCATION) < 0) {
  843. lwsl_notice("%s: Location too large\n",
  844. __func__);
  845. goto failed;
  846. }
  847. ac->kid = ac->acct_id;
  848. lwsl_notice("Location: %s\n", ac->acct_id);
  849. break;
  850. case ACME_STATE_NEW_ORDER:
  851. if (lws_hdr_copy(wsi, ac->order_url,
  852. sizeof(ac->order_url),
  853. WSI_TOKEN_HTTP_LOCATION) < 0) {
  854. lwsl_notice("%s: missing cert location:\n",
  855. __func__);
  856. goto failed;
  857. }
  858. lejp_construct(&ac->jctx, cb_order, ac, jorder_tok,
  859. LWS_ARRAY_SIZE(jorder_tok));
  860. break;
  861. case ACME_STATE_AUTHZ:
  862. lejp_construct(&ac->jctx, cb_authz, ac, jauthz_tok,
  863. LWS_ARRAY_SIZE(jauthz_tok));
  864. break;
  865. case ACME_STATE_START_CHALL:
  866. lejp_construct(&ac->jctx, cb_chac, ac, jchac_tok,
  867. LWS_ARRAY_SIZE(jchac_tok));
  868. break;
  869. case ACME_STATE_POLLING:
  870. case ACME_STATE_POLLING_CSR:
  871. lejp_construct(&ac->jctx, cb_order, ac, jorder_tok,
  872. LWS_ARRAY_SIZE(jorder_tok));
  873. break;
  874. case ACME_STATE_DOWNLOAD_CERT:
  875. ac->cpos = 0;
  876. break;
  877. default:
  878. break;
  879. }
  880. break;
  881. case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
  882. if (!ac)
  883. break;
  884. switch (ac->state) {
  885. case ACME_STATE_DIRECTORY:
  886. case ACME_STATE_NEW_NONCE:
  887. break;
  888. case ACME_STATE_NEW_ACCOUNT:
  889. p += lws_snprintf(p, end - p, "{"
  890. "\"termsOfServiceAgreed\":true"
  891. ",\"contact\": [\"mailto:%s\"]}",
  892. vhd->pvop_active[LWS_TLS_REQ_ELEMENT_EMAIL]);
  893. puts(start);
  894. strcpy(ac->active_url, ac->urls[JAD_NEW_ACCOUNT_URL]);
  895. pkt_add_hdrs:
  896. if (lws_gencrypto_jwe_alg_to_definition("RSA1_5",
  897. &jwe.jose.alg)) {
  898. ac->len = 0;
  899. lwsl_notice("%s: no RSA1_5\n", __func__);
  900. goto failed;
  901. }
  902. jwe.jwk = vhd->jwk;
  903. ac->len = jws_create_packet(&jwe,
  904. start, p - start,
  905. ac->replay_nonce,
  906. ac->active_url,
  907. ac->kid,
  908. &ac->buf[LWS_PRE],
  909. sizeof(ac->buf) - LWS_PRE,
  910. lws_get_context(wsi));
  911. if (ac->len < 0) {
  912. ac->len = 0;
  913. lwsl_notice("jws_create_packet failed\n");
  914. goto failed;
  915. }
  916. pp = (unsigned char **)in;
  917. pend = (*pp) + len;
  918. ac->pos = 0;
  919. content_type = "application/jose+json";
  920. if (lws_add_http_header_by_token(wsi,
  921. WSI_TOKEN_HTTP_CONTENT_TYPE,
  922. (uint8_t *)content_type, 21, pp,
  923. pend)) {
  924. lwsl_notice("could not add content type\n");
  925. goto failed;
  926. }
  927. n = sprintf(buf, "%d", ac->len);
  928. if (lws_add_http_header_by_token(wsi,
  929. WSI_TOKEN_HTTP_CONTENT_LENGTH,
  930. (uint8_t *)buf, n, pp, pend)) {
  931. lwsl_notice("could not add content length\n");
  932. goto failed;
  933. }
  934. lws_client_http_body_pending(wsi, 1);
  935. lws_callback_on_writable(wsi);
  936. break;
  937. case ACME_STATE_NEW_ORDER:
  938. p += lws_snprintf(p, end - p,
  939. "{"
  940. "\"identifiers\":[{"
  941. "\"type\":\"dns\","
  942. "\"value\":\"%s\""
  943. "}]"
  944. "}",
  945. vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);
  946. puts(start);
  947. strcpy(ac->active_url, ac->urls[JAD_NEW_ORDER_URL]);
  948. goto pkt_add_hdrs;
  949. case ACME_STATE_AUTHZ:
  950. puts(start);
  951. strcpy(ac->active_url, ac->authz_url);
  952. goto pkt_add_hdrs;
  953. case ACME_STATE_START_CHALL:
  954. p = start;
  955. end = &buf[sizeof(buf) - 1];
  956. p += lws_snprintf(p, end - p, "{}");
  957. puts(start);
  958. strcpy(ac->active_url, ac->challenge_uri);
  959. goto pkt_add_hdrs;
  960. case ACME_STATE_POLLING:
  961. strcpy(ac->active_url, ac->order_url);
  962. goto pkt_add_hdrs;
  963. case ACME_STATE_POLLING_CSR:
  964. if (ac->goes_around)
  965. break;
  966. p += lws_snprintf(p, end - p, "{\"csr\":\"");
  967. n = lws_tls_acme_sni_csr_create(vhd->context,
  968. &vhd->pvop_active[0],
  969. (uint8_t *)p, end - p,
  970. &ac->alloc_privkey_pem,
  971. &ac->len_privkey_pem);
  972. if (n < 0) {
  973. lwsl_notice("CSR generation failed\n");
  974. goto failed;
  975. }
  976. p += n;
  977. p += lws_snprintf(p, end - p, "\"}");
  978. puts(start);
  979. strcpy(ac->active_url, ac->finalize_url);
  980. goto pkt_add_hdrs;
  981. case ACME_STATE_DOWNLOAD_CERT:
  982. strcpy(ac->active_url, ac->cert_url);
  983. goto pkt_add_hdrs;
  984. break;
  985. default:
  986. break;
  987. }
  988. break;
  989. case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
  990. lwsl_notice("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\n");
  991. if (!ac)
  992. break;
  993. if (ac->pos == ac->len)
  994. break;
  995. ac->buf[LWS_PRE + ac->len] = '\0';
  996. if (lws_write(wsi, (uint8_t *)ac->buf + LWS_PRE,
  997. ac->len, LWS_WRITE_HTTP_FINAL) < 0)
  998. return -1;
  999. lwsl_notice("wrote %d\n", ac->len);
  1000. ac->pos = ac->len;
  1001. lws_client_http_body_pending(wsi, 0);
  1002. break;
  1003. /* chunked content */
  1004. case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
  1005. if (!ac)
  1006. return -1;
  1007. switch (ac->state) {
  1008. case ACME_STATE_POLLING_CSR:
  1009. case ACME_STATE_POLLING:
  1010. case ACME_STATE_START_CHALL:
  1011. case ACME_STATE_AUTHZ:
  1012. case ACME_STATE_NEW_ORDER:
  1013. case ACME_STATE_DIRECTORY:
  1014. ((char *)in)[len] = '\0';
  1015. puts(in);
  1016. m = lejp_parse(&ac->jctx, (uint8_t *)in, len);
  1017. if (m < 0 && m != LEJP_CONTINUE) {
  1018. lwsl_notice("lejp parse failed %d\n", m);
  1019. goto failed;
  1020. }
  1021. break;
  1022. case ACME_STATE_NEW_ACCOUNT:
  1023. ((char *)in)[len] = '\0';
  1024. puts(in);
  1025. break;
  1026. case ACME_STATE_DOWNLOAD_CERT:
  1027. ((char *)in)[len] = '\0';
  1028. puts(in);
  1029. /* it should be the DER cert! */
  1030. if (ac->cpos + len > sizeof(ac->buf)) {
  1031. lwsl_notice("Incoming cert is too large!\n");
  1032. goto failed;
  1033. }
  1034. memcpy(&ac->buf[ac->cpos], in, len);
  1035. ac->cpos += len;
  1036. break;
  1037. default:
  1038. break;
  1039. }
  1040. break;
  1041. /* unchunked content */
  1042. case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
  1043. lwsl_notice("%s: LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n", __func__);
  1044. if (!ac)
  1045. return -1;
  1046. switch (ac->state) {
  1047. default:
  1048. {
  1049. char buffer[2048 + LWS_PRE];
  1050. char *px = buffer + LWS_PRE;
  1051. int lenx = sizeof(buffer) - LWS_PRE;
  1052. if (lws_http_client_read(wsi, &px, &lenx) < 0)
  1053. return -1;
  1054. }
  1055. break;
  1056. }
  1057. break;
  1058. case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
  1059. lwsl_notice("%s: COMPLETED_CLIENT_HTTP\n", __func__);
  1060. if (!ac)
  1061. return -1;
  1062. switch (ac->state) {
  1063. case ACME_STATE_DIRECTORY:
  1064. lejp_destruct(&ac->jctx);
  1065. /* check dir validity */
  1066. for (n = 0; n < 6; n++)
  1067. lwsl_notice(" %d: %s\n", n, ac->urls[n]);
  1068. ac->state = ACME_STATE_NEW_NONCE;
  1069. strcpy(buf, ac->urls[JAD_NEW_NONCE_URL]);
  1070. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1071. &ac->cwsi, &ac->i, buf,
  1072. "GET");
  1073. if (!cwsi) {
  1074. lwsl_notice("%s: failed to connect to acme\n",
  1075. __func__);
  1076. goto failed;
  1077. }
  1078. return -1; /* close the completed client connection */
  1079. case ACME_STATE_NEW_ACCOUNT:
  1080. if ((ac->resp >= 200 && ac->resp < 299) ||
  1081. ac->resp == 409) {
  1082. /*
  1083. * Our account already existed, or exists now.
  1084. *
  1085. */
  1086. ac->state = ACME_STATE_NEW_ORDER;
  1087. strcpy(buf, ac->urls[JAD_NEW_ORDER_URL]);
  1088. cwsi = lws_acme_client_connect(vhd->context,
  1089. vhd->vhost, &ac->cwsi,
  1090. &ac->i, buf, "POST");
  1091. if (!cwsi)
  1092. lwsl_notice("%s: failed to connect\n",
  1093. __func__);
  1094. /* close the completed client connection */
  1095. return -1;
  1096. } else {
  1097. lwsl_notice("newAccount replied %d\n",
  1098. ac->resp);
  1099. goto failed;
  1100. }
  1101. return -1; /* close the completed client connection */
  1102. case ACME_STATE_NEW_ORDER:
  1103. lejp_destruct(&ac->jctx);
  1104. if (!ac->authz_url[0]) {
  1105. lwsl_notice("no authz\n");
  1106. goto failed;
  1107. }
  1108. /*
  1109. * Move on to requesting a cert auth.
  1110. */
  1111. ac->state = ACME_STATE_AUTHZ;
  1112. lws_acme_report_status(vhd->vhost, LWS_CUS_AUTH,
  1113. NULL);
  1114. strcpy(buf, ac->authz_url);
  1115. cwsi = lws_acme_client_connect(vhd->context,
  1116. vhd->vhost, &ac->cwsi,
  1117. &ac->i, buf, "POST");
  1118. if (!cwsi)
  1119. lwsl_notice("%s: failed to connect\n",
  1120. __func__);
  1121. return -1; /* close the completed client connection */
  1122. case ACME_STATE_AUTHZ:
  1123. lejp_destruct(&ac->jctx);
  1124. if (ac->resp / 100 == 4) {
  1125. lws_snprintf(buf, sizeof(buf),
  1126. "Auth failed: %s", ac->detail);
  1127. failreason = buf;
  1128. lwsl_notice("auth failed\n");
  1129. goto failed;
  1130. }
  1131. lwsl_notice("chall: %s (%d)\n", ac->chall_token,
  1132. ac->resp);
  1133. if (!ac->chall_token[0]) {
  1134. lwsl_notice("no challenge\n");
  1135. goto failed;
  1136. }
  1137. ac->state = ACME_STATE_START_CHALL;
  1138. lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE,
  1139. NULL);
  1140. memset(&ac->ci, 0, sizeof(ac->ci));
  1141. /* compute the key authorization */
  1142. p = ac->key_auth;
  1143. end = p + sizeof(ac->key_auth) - 1;
  1144. p += lws_snprintf(p, end - p, "%s.", ac->chall_token);
  1145. lws_jwk_rfc7638_fingerprint(&vhd->jwk, digest);
  1146. n = lws_jws_base64_enc(digest, 32, p, end - p);
  1147. if (n < 0)
  1148. goto failed;
  1149. lwsl_notice("key_auth: '%s'\n", ac->key_auth);
  1150. lws_snprintf(ac->http01_mountpoint,
  1151. sizeof(ac->http01_mountpoint),
  1152. "/.well-known/acme-challenge/%s",
  1153. ac->chall_token);
  1154. memset(&ac->mount, 0, sizeof (struct lws_http_mount));
  1155. ac->mount.protocol = "http";
  1156. ac->mount.mountpoint = ac->http01_mountpoint;
  1157. ac->mount.mountpoint_len =
  1158. strlen(ac->http01_mountpoint);
  1159. ac->mount.origin_protocol = LWSMPRO_CALLBACK;
  1160. ac->ci.mounts = &ac->mount;
  1161. /* listen on the same port as the vhost that triggered
  1162. * us */
  1163. ac->ci.port = 80;
  1164. /* make ourselves protocols[0] for the new vhost */
  1165. ac->ci.protocols = chall_http01_protocols;
  1166. /*
  1167. * vhost .user points to the ac associated with the
  1168. * temporary vhost
  1169. */
  1170. ac->ci.user = ac;
  1171. ac->vhost = lws_create_vhost(lws_get_context(wsi),
  1172. &ac->ci);
  1173. if (!ac->vhost)
  1174. goto failed;
  1175. lwsl_notice("challenge_uri %s\n", ac->challenge_uri);
  1176. /*
  1177. * The challenge-specific vhost is up... let the ACME
  1178. * server know we are ready to roll...
  1179. */
  1180. ac->goes_around = 0;
  1181. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1182. &ac->cwsi, &ac->i,
  1183. ac->challenge_uri,
  1184. "POST");
  1185. if (!cwsi) {
  1186. lwsl_notice("%s: connect failed\n", __func__);
  1187. goto failed;
  1188. }
  1189. return -1; /* close the completed client connection */
  1190. case ACME_STATE_START_CHALL:
  1191. lwsl_notice("%s: COMPLETED start chall: %s\n",
  1192. __func__, ac->challenge_uri);
  1193. poll_again:
  1194. ac->state = ACME_STATE_POLLING;
  1195. lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE,
  1196. NULL);
  1197. if (ac->goes_around++ == 20) {
  1198. lwsl_notice("%s: too many chall retries\n",
  1199. __func__);
  1200. goto failed;
  1201. }
  1202. strcpy(buf, ac->order_url);
  1203. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1204. &ac->cwsi, &ac->i, buf,
  1205. "POST");
  1206. if (!cwsi) {
  1207. lwsl_notice("%s: failed to connect to acme\n",
  1208. __func__);
  1209. goto failed;
  1210. }
  1211. return -1; /* close the completed client connection */
  1212. case ACME_STATE_POLLING:
  1213. if (ac->resp == 202 && strcmp(ac->status, "invalid") &&
  1214. strcmp(ac->status, "valid")) {
  1215. lwsl_notice("status: %s\n", ac->status);
  1216. goto poll_again;
  1217. }
  1218. if (!strcmp(ac->status, "pending")) {
  1219. lwsl_notice("status: %s\n", ac->status);
  1220. goto poll_again;
  1221. }
  1222. if (!strcmp(ac->status, "invalid")) {
  1223. lwsl_notice("%s: Challenge failed\n", __func__);
  1224. lws_snprintf(buf, sizeof(buf),
  1225. "Challenge Invalid: %s",
  1226. ac->detail);
  1227. failreason = buf;
  1228. goto failed;
  1229. }
  1230. lwsl_notice("Challenge passed\n");
  1231. /*
  1232. * The challenge was validated... so delete the
  1233. * temp vhost now its job is done
  1234. */
  1235. if (ac->vhost)
  1236. lws_vhost_destroy(ac->vhost);
  1237. ac->vhost = NULL;
  1238. /*
  1239. * now our JWK is accepted as authorized to make
  1240. * requests for the domain, next move is create the
  1241. * CSR signed with the JWK, and send it to the ACME
  1242. * server to request the actual certs.
  1243. */
  1244. ac->state = ACME_STATE_POLLING_CSR;
  1245. lws_acme_report_status(vhd->vhost, LWS_CUS_REQ, NULL);
  1246. ac->goes_around = 0;
  1247. strcpy(buf, ac->finalize_url);
  1248. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1249. &ac->cwsi, &ac->i, buf,
  1250. "POST");
  1251. if (!cwsi) {
  1252. lwsl_notice("%s: failed to connect to acme\n",
  1253. __func__);
  1254. goto failed;
  1255. }
  1256. return -1; /* close the completed client connection */
  1257. case ACME_STATE_POLLING_CSR:
  1258. if (ac->resp < 200 || ac->resp > 202) {
  1259. lwsl_notice("CSR poll failed on resp %d\n",
  1260. ac->resp);
  1261. goto failed;
  1262. }
  1263. if (ac->resp != 200) {
  1264. if (ac->goes_around++ == 30) {
  1265. lwsl_notice("%s: too many retries\n",
  1266. __func__);
  1267. goto failed;
  1268. }
  1269. strcpy(buf, ac->finalize_url);
  1270. cwsi = lws_acme_client_connect(vhd->context,
  1271. vhd->vhost,
  1272. &ac->cwsi, &ac->i, buf,
  1273. "POST");
  1274. if (!cwsi) {
  1275. lwsl_notice("%s: "
  1276. "failed to connect to acme\n",
  1277. __func__);
  1278. goto failed;
  1279. }
  1280. /* close the completed client connection */
  1281. return -1;
  1282. }
  1283. ac->state = ACME_STATE_DOWNLOAD_CERT;
  1284. strcpy(buf, ac->cert_url);
  1285. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1286. &ac->cwsi, &ac->i, buf,
  1287. "POST");
  1288. if (!cwsi) {
  1289. lwsl_notice("%s: failed to connect to acme\n",
  1290. __func__);
  1291. goto failed;
  1292. }
  1293. return -1;
  1294. case ACME_STATE_DOWNLOAD_CERT:
  1295. if (ac->resp != 200) {
  1296. lwsl_notice("download cert failed on resp %d\n",
  1297. ac->resp);
  1298. goto failed;
  1299. }
  1300. lwsl_notice("The cert was sent..\n");
  1301. lws_acme_report_status(vhd->vhost, LWS_CUS_ISSUE, NULL);
  1302. /*
  1303. * That means we have the issued cert in
  1304. * ac->buf, length in ac->cpos; and the key in
  1305. * ac->alloc_privkey_pem, length in
  1306. * ac->len_privkey_pem.
  1307. */
  1308. n = lws_plat_write_cert(vhd->vhost, 0,
  1309. vhd->fd_updated_cert,
  1310. ac->buf,
  1311. ac->cpos);
  1312. if (n) {
  1313. lwsl_err("unable to write ACME cert! %d\n", n);
  1314. goto failed;
  1315. }
  1316. /*
  1317. * don't close it... we may update the certs
  1318. * again
  1319. */
  1320. if (lws_plat_write_cert(vhd->vhost, 1,
  1321. vhd->fd_updated_key,
  1322. ac->alloc_privkey_pem,
  1323. ac->len_privkey_pem)) {
  1324. lwsl_err("unable to write ACME key!\n");
  1325. goto failed;
  1326. }
  1327. /*
  1328. * we have written the persistent copies
  1329. */
  1330. lwsl_notice("%s: Updated certs written for %s "
  1331. "to %s.upd and %s.upd\n", __func__,
  1332. vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
  1333. vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
  1334. vhd->pvop_active[LWS_TLS_SET_KEY_PATH]);
  1335. /* notify lws there was a cert update */
  1336. if (lws_tls_cert_updated(vhd->context,
  1337. vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
  1338. vhd->pvop_active[LWS_TLS_SET_KEY_PATH],
  1339. ac->buf, ac->cpos,
  1340. ac->alloc_privkey_pem,
  1341. ac->len_privkey_pem)) {
  1342. lwsl_notice("problem setting certs\n");
  1343. }
  1344. lws_acme_finished(vhd);
  1345. lws_acme_report_status(vhd->vhost,
  1346. LWS_CUS_SUCCESS, NULL);
  1347. return -1;
  1348. default:
  1349. break;
  1350. }
  1351. break;
  1352. case LWS_CALLBACK_USER + 0xac33:
  1353. if (!vhd)
  1354. break;
  1355. cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
  1356. &ac->cwsi, &ac->i,
  1357. ac->challenge_uri,
  1358. "GET");
  1359. if (!cwsi) {
  1360. lwsl_notice("%s: failed to connect\n", __func__);
  1361. goto failed;
  1362. }
  1363. break;
  1364. default:
  1365. break;
  1366. }
  1367. return 0;
  1368. failed:
  1369. lwsl_notice("%s: failed out\n", __func__);
  1370. lws_acme_report_status(vhd->vhost, LWS_CUS_FAILED, failreason);
  1371. lws_acme_finished(vhd);
  1372. return -1;
  1373. }
  1374. #if !defined (LWS_PLUGIN_STATIC)
  1375. static const struct lws_protocols protocols[] = {
  1376. LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT
  1377. };
  1378. LWS_VISIBLE const lws_plugin_protocol_t protocol_lws_acme_client = {
  1379. .hdr = {
  1380. "acme client",
  1381. "lws_protocol_plugin",
  1382. LWS_PLUGIN_API_MAGIC
  1383. },
  1384. .protocols = protocols,
  1385. .count_protocols = LWS_ARRAY_SIZE(protocols),
  1386. .extensions = NULL,
  1387. .count_extensions = 0,
  1388. };
  1389. #endif