Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1745908453, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"e2464e28cbeb168f3dd42dc2f05d9ded", "commit": {"type":"commit", "time": 1572875353, "time_ofs": 0, "oid_tree": { "oid": "3c92326b3fa9186e6288114cd2b131271dc41abd", "alias": []}, "oid":{ "oid": "37898cc3f313c78759d2cbc1c1ae8f6db76034ef", "alias": []}, "msg": "acme: convert from tls-sni-01 to ACMEv2 http-01", "sig_commit": { "git_time": { "time": 1572875353, "offset": 0 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }, "sig_author": { "git_time": { "time": 1572839740, "offset": 480 }, "name": "Zhiwen Zheng", "email": "zhiwen.zh@gmail.com", "md5": "2e9d87835eba409045f98e1c9ee16438" }}, "body": "acme: convert from tls-sni-01 to ACMEv2 http-01" , "diff": "diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c\nindex e21628e..5db2b48 100644\n--- a/plugins/acme-client/protocol_lws_acme_client.c\n+++ b/plugins/acme-client/protocol_lws_acme_client.c\n@@ -43,12 +43,15 @@\n #include \u003cstdlib.h\u003e\n \n typedef enum {\n-\tACME_STATE_DIRECTORY,\t /* get the directory JSON using GET + parse */\n-\tACME_STATE_NEW_REG,\t /* register a new RSA key + email combo */\n-\tACME_STATE_NEW_AUTH,\t /* start the process to request a cert */\n-\tACME_STATE_ACCEPT_CHALL, /* notify server ready for one challenge */\n-\tACME_STATE_POLLING,\t /* he should be trying our challenge */\n-\tACME_STATE_POLLING_CSR,\t /* sent CSR, checking result */\n+\tACME_STATE_DIRECTORY,\t/* get the directory JSON using GET + parse */\n+\tACME_STATE_NEW_NONCE,\t/* get the replay nonce */\n+\tACME_STATE_NEW_ACCOUNT,\t/* register a new RSA key + email combo */\n+\tACME_STATE_NEW_ORDER,\t/* start the process to request a cert */\n+\tACME_STATE_AUTHZ,\t/* */\n+\tACME_STATE_START_CHALL, /* notify server ready for one challenge */\n+\tACME_STATE_POLLING,\t/* he should be trying our challenge */\n+\tACME_STATE_POLLING_CSR,\t/* sent CSR, checking result */\n+\tACME_STATE_DOWNLOAD_CERT,\n \n \tACME_STATE_FINISHED\n } lws_acme_state;\n@@ -60,9 +63,17 @@ struct acme_connection {\n \tchar challenge_uri[256];\n \tchar detail[64];\n \tchar status[16];\n-\tchar san_a[100];\n-\tchar san_b[100];\n+\tchar key_auth[256];\n+\tchar http01_mountpoint[256];\n+\tstruct lws_http_mount mount;\n \tchar urls[6][100]; /* directory contents */\n+\tchar active_url[100];\n+\tchar authz_url[100];\n+\tchar order_url[100];\n+\tchar finalize_url[100];\n+\tchar cert_url[100];\n+\tchar acct_id[100];\n+\tchar *kid;\n \tlws_acme_state state;\n \tstruct lws_client_connect_info i;\n \tstruct lejp_ctx jctx;\n@@ -119,52 +130,230 @@ struct per_vhost_data__lws_acme_client {\n };\n \n static int\n-callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n-\t\t void *user, void *in, size_t len);\n+callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason,\n+ void *user, void *in, size_t len)\n+{\n+\tstruct lws_vhost *vhost \u003d lws_get_vhost(wsi);\n+\tstruct acme_connection *ac \u003d lws_vhost_user(vhost);\n+\tuint8_t buf[LWS_PRE + 2048], *start \u003d \u0026buf[LWS_PRE], *p \u003d start,\n+\t\t*end \u003d \u0026buf[sizeof(buf) - LWS_PRE - 1];\n+\tint n;\n \n-#define LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT \u005c\n-\t{ \u005c\n-\t\t\u0022lws-acme-client\u0022, \u005c\n-\t\tcallback_acme_client, \u005c\n-\t\t0, \u005c\n-\t\t512, \u005c\n-\t\t0, NULL, 0 \u005c\n+\tswitch (reason) {\n+\tcase LWS_CALLBACK_HTTP:\n+\t\tlwsl_notice(\u0022%s: ca connection received, key_auth %s\u005cn\u0022,\n+\t\t\t __func__, ac-\u003ekey_auth);\n+\n+\t\tif (lws_add_http_header_status(wsi, HTTP_STATUS_OK, \u0026p, end)) {\n+\t\t\tlwsl_notice(\u0022%s: add status failed\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_TYPE,\n+\t\t\t\t\t(unsigned char *)\u0022text/plain\u0022, 10,\n+\t\t\t\t\t\u0026p, end)) {\n+\t\t\tlwsl_notice(\u0022%s: add content_type failed\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tn \u003d strlen(ac-\u003ekey_auth);\n+\t\tif (lws_add_http_header_content_length(wsi, n, \u0026p, end)) {\n+\t\t\tlwsl_notice(\u0022%s: add content_length failed\u005cn\u0022,\n+\t\t\t\t\t__func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (lws_add_http_header_by_token(wsi,\n+\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_DISPOSITION,\n+\t\t\t\t\t(unsigned char *)\u0022attachment\u0022, 10,\n+\t\t\t\t\t\u0026p, end)) {\n+\t\t\tlwsl_notice(\u0022%s: add content_dispo failed\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (lws_finalize_write_http_header(wsi, start, \u0026p, end)) {\n+\t\t\tlwsl_notice(\u0022%s: finalize http header failed\u005cn\u0022,\n+\t\t\t\t\t__func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tlws_callback_on_writable(wsi);\n+\t\treturn 0;\n+\n+\tcase LWS_CALLBACK_HTTP_WRITEABLE:\n+\t\tp +\u003d lws_snprintf((char *)p, end - p, \u0022%s\u0022, ac-\u003ekey_auth);\n+\t\tlwsl_notice(\u0022%s: len %d\u005cn\u0022, __func__, lws_ptr_diff(p, start));\n+\t\tif (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start),\n+\t\t\t LWS_WRITE_HTTP_FINAL) !\u003d lws_ptr_diff(p, start)) {\n+\t\t\tlwsl_err(\u0022_write content failed\u005cn\u0022);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (lws_http_transaction_completed(wsi))\n+\t\t\treturn -1;\n+\n+\t\treturn 0;\n+\n+\tdefault:\n+\t\tbreak;\n \t}\n \n-static const struct lws_protocols acme_protocols[] \u003d {\n-\tLWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT,\n+\treturn lws_callback_http_dummy(wsi, reason, user, in, len);\n+}\n+\n+static const struct lws_protocols chall_http01_protocols[] \u003d {\n+\t{ \u0022http\u0022, callback_chall_http01, 0, 0, 0, NULL, 0 },\n \t{ NULL, NULL, 0, 0, 0, NULL, 0 }\n };\n \n+static int\n+jws_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,\n+\t\t const char *nonce, const char *url, const char *kid,\n+\t\t char *out, size_t out_len, struct lws_context *context)\n+{\n+\tchar *buf, *start, *p, *end, *p1, *end1;\n+\tstruct lws_jws jws;\n+\tint n, m;\n+\n+\tlws_jws_init(\u0026jws, \u0026jwe-\u003ejwk, context);\n+\n+\t/*\n+\t * This buffer is local to the function, the actual output is prepared\n+\t * into out. Only the plaintext protected header\n+\t * (which contains the public key, 512 bytes for 4096b) goes in\n+\t * here temporarily.\n+\t */\n+\tn \u003d LWS_PRE + 2048;\n+\tbuf \u003d malloc(n);\n+\tif (!buf) {\n+\t\tlwsl_notice(\u0022%s: malloc %d failed\u005cn\u0022, __func__, n);\n+\t\treturn -1;\n+\t}\n+\n+\tp \u003d start \u003d buf + LWS_PRE;\n+\tend \u003d buf + n - LWS_PRE - 1;\n+\n+\t/*\n+\t * temporary JWS protected header plaintext\n+\t */\n+\tif (!jwe-\u003ejose.alg || !jwe-\u003ejose.alg-\u003ealg)\n+\t\tgoto bail;\n+\n+\tp +\u003d lws_snprintf(p, end - p, \u0022{\u005c\u0022alg\u005c\u0022:\u005c\u0022RS256\u005c\u0022\u0022);\n+\tif (kid)\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022kid\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022, kid);\n+\telse {\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022jwk\u005c\u0022:\u0022);\n+\t\tm \u003d end - p;\n+\t\tn \u003d lws_jwk_export(\u0026jwe-\u003ejwk, 0, p, \u0026m);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_notice(\u0022failed to export jwk\u005cn\u0022);\n+\t\t\tgoto bail;\n+\t\t}\n+\t\tp +\u003d n;\n+\t}\n+\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022url\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022, url);\n+\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022nonce\u005c\u0022:\u005c\u0022%s\u005c\u0022}\u0022, nonce);\n+\n+\t/*\n+\t * prepare the signed outer JSON with all the parts in\n+\t */\n+\tp1 \u003d out;\n+\tend1 \u003d out + out_len - 1;\n+\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022{\u005c\u0022protected\u005c\u0022:\u005c\u0022\u0022);\n+\tjws.map_b64.buf[LJWS_JOSE] \u003d p1;\n+\tn \u003d lws_jws_base64_enc(start, p - start, p1, end1 - p1);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: failed to encode protected\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\tjws.map_b64.len[LJWS_JOSE] \u003d n;\n+\tp1 +\u003d n;\n+\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022payload\u005c\u0022:\u005c\u0022\u0022);\n+\tjws.map_b64.buf[LJWS_PYLD] \u003d p1;\n+\tn \u003d lws_jws_base64_enc(payload, len, p1, end1 - p1);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: failed to encode payload\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\tjws.map_b64.len[LJWS_PYLD] \u003d n;\n+\tp1 +\u003d n;\n+\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022signature\u005c\u0022:\u005c\u0022\u0022);\n+\n+\t/*\n+\t * taking the b64 protected header and the b64 payload, sign them\n+\t * and place the signature into the packet\n+\t */\n+\tn \u003d lws_jws_sign_from_b64(\u0026jwe-\u003ejose, \u0026jws, p1, end1 - p1);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022sig gen failed\u005cn\u0022);\n+\n+\t\tgoto bail;\n+\t}\n+\tjws.map_b64.buf[LJWS_SIG] \u003d p1;\n+\tjws.map_b64.len[LJWS_SIG] \u003d n;\n+\n+\tp1 +\u003d n;\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022}\u0022);\n+\n+\tfree(buf);\n+\n+\treturn p1 - out;\n+\n+bail:\n+\tlws_jws_destroy(\u0026jws);\n+\tfree(buf);\n+\n+\treturn -1;\n+}\n+\n+static int\n+callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n+\t\tvoid *user, void *in, size_t len);\n+\n+#define LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT \u005c\n+{ \u005c\n+\t\u0022lws-acme-client\u0022, \u005c\n+\tcallback_acme_client, \u005c\n+\t0, \u005c\n+\t512, \u005c\n+\t0, NULL, 0 \u005c\n+}\n+\n /* directory JSON parsing */\n \n static const char * const jdir_tok[] \u003d {\n-\t\u0022key-change\u0022,\n-\t\u0022meta.terms-of-service\u0022,\n-\t\u0022new-authz\u0022,\n-\t\u0022new-cert\u0022,\n-\t\u0022new-reg\u0022,\n-\t\u0022revoke-cert\u0022,\n+\t\u0022keyChange\u0022,\n+\t\u0022meta.termsOfService\u0022,\n+\t\u0022newAccount\u0022,\n+\t\u0022newNonce\u0022,\n+\t\u0022newOrder\u0022,\n+\t\u0022revokeCert\u0022,\n };\n-enum enum_jhdr_tok {\n+\n+enum enum_jdir_tok {\n \tJAD_KEY_CHANGE_URL,\n \tJAD_TOS_URL,\n-\tJAD_NEW_AUTHZ_URL,\n-\tJAD_NEW_CERT_URL,\n-\tJAD_NEW_REG_URL,\n+\tJAD_NEW_ACCOUNT_URL,\n+\tJAD_NEW_NONCE_URL,\n+\tJAD_NEW_ORDER_URL,\n \tJAD_REVOKE_CERT_URL,\n };\n+\n static signed char\n cb_dir(struct lejp_ctx *ctx, char reason)\n {\n \tstruct per_vhost_data__lws_acme_client *s \u003d\n-\t\t\t(struct per_vhost_data__lws_acme_client *)ctx-\u003euser;\n+\t\t(struct per_vhost_data__lws_acme_client *)ctx-\u003euser;\n \n \tif (reason \u003d\u003d LEJPCB_VAL_STR_START \u0026\u0026 ctx-\u003epath_match) {\n \t\ts-\u003epos \u003d 0;\n \t\ts-\u003elen \u003d sizeof(s-\u003eac-\u003eurls[0]) - 1;\n \t\ts-\u003edest \u003d s-\u003eac-\u003eurls[ctx-\u003epath_match - 1];\n-\n \t\treturn 0;\n \t}\n \n@@ -173,7 +362,6 @@ cb_dir(struct lejp_ctx *ctx, char reason)\n \n \tif (s-\u003epos + ctx-\u003enpos \u003e s-\u003elen) {\n \t\tlwsl_notice(\u0022url too long\u005cn\u0022);\n-\n \t\treturn -1;\n \t}\n \n@@ -184,6 +372,66 @@ cb_dir(struct lejp_ctx *ctx, char reason)\n \treturn 0;\n }\n \n+\n+/* order JSON parsing */\n+\n+static const char * const jorder_tok[] \u003d {\n+\t\u0022status\u0022,\n+\t\u0022expires\u0022,\n+\t\u0022identifiers[].type\u0022,\n+\t\u0022identifiers[].value\u0022,\n+\t\u0022authorizations\u0022,\n+\t\u0022finalize\u0022,\n+\t\u0022certificate\u0022\n+};\n+\n+enum enum_jorder_tok {\n+\tJAO_STATUS,\n+\tJAO_EXPIRES,\n+\tJAO_IDENTIFIERS_TYPE,\n+\tJAO_IDENTIFIERS_VALUE,\n+\tJAO_AUTHORIZATIONS,\n+\tJAO_FINALIZE,\n+\tJAO_CERT\n+};\n+\n+static signed char\n+cb_order(struct lejp_ctx *ctx, char reason)\n+{\n+\tstruct acme_connection *s \u003d (struct acme_connection *)ctx-\u003euser;\n+\n+\tif (reason \u003d\u003d LEJPCB_CONSTRUCTED)\n+\t\ts-\u003eauthz_url[0] \u003d '\u005c0';\n+\n+\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n+\t\treturn 0;\n+\n+\tswitch (ctx-\u003epath_match - 1) {\n+\tcase JAO_STATUS:\n+\t\tlws_strncpy(s-\u003estatus, ctx-\u003ebuf, sizeof(s-\u003estatus));\n+\t\tbreak;\n+\tcase JAO_EXPIRES:\n+\t\tbreak;\n+\tcase JAO_IDENTIFIERS_TYPE:\n+\t\tbreak;\n+\tcase JAO_IDENTIFIERS_VALUE:\n+\t\tbreak;\n+\tcase JAO_AUTHORIZATIONS:\n+\t\tlws_snprintf(s-\u003eauthz_url, sizeof(s-\u003eauthz_url), \u0022%s\u0022,\n+\t\t\t ctx-\u003ebuf);\n+\t\tbreak;\n+\tcase JAO_FINALIZE:\n+\t\tlws_snprintf(s-\u003efinalize_url, sizeof(s-\u003efinalize_url), \u0022%s\u0022,\n+\t\t\t\tctx-\u003ebuf);\n+\t\tbreak;\n+\tcase JAO_CERT:\n+\t\tlws_snprintf(s-\u003ecert_url, sizeof(s-\u003ecert_url), \u0022%s\u0022, ctx-\u003ebuf);\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /* authz JSON parsing */\n \n static const char * const jauthz_tok[] \u003d {\n@@ -193,10 +441,11 @@ static const char * const jauthz_tok[] \u003d {\n \t\u0022expires\u0022,\n \t\u0022challenges[].type\u0022,\n \t\u0022challenges[].status\u0022,\n-\t\u0022challenges[].uri\u0022,\n+\t\u0022challenges[].url\u0022,\n \t\u0022challenges[].token\u0022,\n \t\u0022detail\u0022\n };\n+\n enum enum_jauthz_tok {\n \tJAAZ_ID_TYPE,\n \tJAAZ_ID_VALUE,\n@@ -204,10 +453,11 @@ enum enum_jauthz_tok {\n \tJAAZ_EXPIRES,\n \tJAAZ_CHALLENGES_TYPE,\n \tJAAZ_CHALLENGES_STATUS,\n-\tJAAZ_CHALLENGES_URI,\n+\tJAAZ_CHALLENGES_URL,\n \tJAAZ_CHALLENGES_TOKEN,\n \tJAAZ_DETAIL,\n };\n+\n static signed char\n cb_authz(struct lejp_ctx *ctx, char reason)\n {\n@@ -217,7 +467,6 @@ cb_authz(struct lejp_ctx *ctx, char reason)\n \t\ts-\u003eyes \u003d 0;\n \t\ts-\u003euse \u003d 0;\n \t\ts-\u003echall_token[0] \u003d '\u005c0';\n-\t\ts-\u003eis_sni_02 \u003d 0;\n \t}\n \n \tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n@@ -236,19 +485,17 @@ cb_authz(struct lejp_ctx *ctx, char reason)\n \t\tlws_snprintf(s-\u003edetail, sizeof(s-\u003edetail), \u0022%s\u0022, ctx-\u003ebuf);\n \t\tbreak;\n \tcase JAAZ_CHALLENGES_TYPE:\n-\t\tif (s-\u003eis_sni_02)\n-\t\t\tbreak;\n-\t\ts-\u003euse \u003d !strcmp(ctx-\u003ebuf, \u0022tls-sni-01\u0022) ||\n-\t\t\t !strcmp(ctx-\u003ebuf, \u0022tls-sni-02\u0022);\n-\t\ts-\u003eis_sni_02 \u003d !strcmp(ctx-\u003ebuf, \u0022tls-sni-02\u0022);\n+\t\tlwsl_notice(\u0022JAAZ_CHALLENGES_TYPE: %s\u005cn\u0022, ctx-\u003ebuf);\n+\t\ts-\u003euse \u003d !strcmp(ctx-\u003ebuf, \u0022http-01\u0022);\n \t\tbreak;\n \tcase JAAZ_CHALLENGES_STATUS:\n \t\tlws_strncpy(s-\u003estatus, ctx-\u003ebuf, sizeof(s-\u003estatus));\n \t\tbreak;\n-\tcase JAAZ_CHALLENGES_URI:\n+\tcase JAAZ_CHALLENGES_URL:\n+\t\tlwsl_notice(\u0022JAAZ_CHALLENGES_URL: %s %d\u005cn\u0022, ctx-\u003ebuf, s-\u003euse);\n \t\tif (s-\u003euse) {\n \t\t\tlws_strncpy(s-\u003echallenge_uri, ctx-\u003ebuf,\n-\t\t\t\tsizeof(s-\u003echallenge_uri));\n+\t\t\t\t sizeof(s-\u003echallenge_uri));\n \t\t\ts-\u003eyes |\u003d 2;\n \t\t}\n \t\tbreak;\n@@ -256,7 +503,7 @@ cb_authz(struct lejp_ctx *ctx, char reason)\n \t\tlwsl_notice(\u0022JAAZ_CHALLENGES_TOKEN: %s %d\u005cn\u0022, ctx-\u003ebuf, s-\u003euse);\n \t\tif (s-\u003euse) {\n \t\t\tlws_strncpy(s-\u003echall_token, ctx-\u003ebuf,\n-\t\t\t\tsizeof(s-\u003echall_token));\n+\t\t\t\t sizeof(s-\u003echall_token));\n \t\t\ts-\u003eyes |\u003d 1;\n \t\t}\n \t\tbreak;\n@@ -274,6 +521,7 @@ static const char * const jchac_tok[] \u003d {\n \t\u0022token\u0022,\n \t\u0022error.detail\u0022\n };\n+\n enum enum_jchac_tok {\n \tJCAC_TYPE,\n \tJCAC_STATUS,\n@@ -281,6 +529,7 @@ enum enum_jchac_tok {\n \tJCAC_TOKEN,\n \tJCAC_DETAIL,\n };\n+\n static signed char\n cb_chac(struct lejp_ctx *ctx, char reason)\n {\n@@ -296,8 +545,7 @@ cb_chac(struct lejp_ctx *ctx, char reason)\n \n \tswitch (ctx-\u003epath_match - 1) {\n \tcase JCAC_TYPE:\n-\t\tif (strcmp(ctx-\u003ebuf, \u0022tls-sni-01\u0022) \u0026\u0026\n-\t\t strcmp(ctx-\u003ebuf, \u0022tls-sni-02\u0022))\n+\t\tif (strcmp(ctx-\u003ebuf, \u0022http-01\u0022))\n \t\t\treturn 1;\n \t\tbreak;\n \tcase JCAC_STATUS:\n@@ -307,8 +555,7 @@ cb_chac(struct lejp_ctx *ctx, char reason)\n \t\ts-\u003eyes |\u003d 2;\n \t\tbreak;\n \tcase JCAC_TOKEN:\n-\t\tlws_strncpy(s-\u003echall_token, ctx-\u003ebuf,\n-\t\t\t\tsizeof(s-\u003echall_token));\n+\t\tlws_strncpy(s-\u003echall_token, ctx-\u003ebuf, sizeof(s-\u003echall_token));\n \t\ts-\u003eyes |\u003d 1;\n \t\tbreak;\n \tcase JCAC_DETAIL:\n@@ -319,29 +566,6 @@ cb_chac(struct lejp_ctx *ctx, char reason)\n \treturn 0;\n }\n \n-/* https://github.com/letsencrypt/boulder/blob/release/docs/acme-divergences.md\n- *\n- * 7.1:\n- *\n- * Boulder does not implement the new-order resource.\n- * Instead of new-order Boulder implements the new-cert resource that is\n- * defined in draft-ietf-acme-02 Section 6.5.\n- *\n- * Boulder also doesn't implement the new-nonce endpoint.\n- *\n- * Boulder implements the new-account resource only under the new-reg key.\n- *\n- * Boulder implements Link: rel\u003d\u0022next\u0022 headers from new-reg to new-authz, and\n- * new-authz to new-cert, as specified in draft-02, but these links are not\n- * provided in the latest draft, and clients should use URLs from the directory\n- * instead.\n- *\n- * Boulder does not provide the \u0022index\u0022 link relation pointing at the\n- * directory URL.\n- *\n- * (ie, just use new-cert instead of new-order, use the directory for links)\n- */\n-\n static int\n lws_acme_report_status(struct lws_vhost *v, int state, const char *json)\n {\n@@ -356,8 +580,8 @@ lws_acme_report_status(struct lws_vhost *v, int state, const char *json)\n */\n static struct lws *\n lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,\n-\t\t\tstruct lws **pwsi, struct lws_client_connect_info *i,\n-\t\t\tchar *url, const char *method)\n+\t\tstruct lws **pwsi, struct lws_client_connect_info *i,\n+\t\tchar *url, const char *method)\n {\n \tconst char *prot, *p;\n \tchar path[200], _url[256];\n@@ -378,7 +602,7 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,\n \ti-\u003epath \u003d path;\n \ti-\u003econtext \u003d context;\n \ti-\u003evhost \u003d vh;\n-\ti-\u003essl_connection \u003d 1;\n+\ti-\u003essl_connection \u003d LCCSCF_USE_SSL;\n \ti-\u003ehost \u003d i-\u003eaddress;\n \ti-\u003eorigin \u003d i-\u003eaddress;\n \ti-\u003emethod \u003d method;\n@@ -399,7 +623,7 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,\n static void\n lws_acme_finished(struct per_vhost_data__lws_acme_client *vhd)\n {\n-\tlwsl_debug(\u0022%s\u005cn\u0022, __func__);\n+\tlwsl_notice(\u0022%s\u005cn\u0022, __func__);\n \n \tif (vhd-\u003eac) {\n \t\tif (vhd-\u003eac-\u003evhost)\n@@ -433,32 +657,30 @@ static const char * const pvo_names[] \u003d {\n \n static int\n lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,\n-\t\t\t int bits)\n+\t\tint bits)\n {\n \tint n;\n \n \tif (!lws_jwk_load(\u0026vhd-\u003ejwk, vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH],\n-\t\t\t NULL, NULL))\n+\t\t\t\tNULL, NULL))\n \t\treturn 0;\n \n \tvhd-\u003ejwk.kty \u003d LWS_GENCRYPTO_KTY_RSA;\n+\n \tlwsl_notice(\u0022Generating ACME %d-bit keypair... \u0022\n-\t\t \u0022will take a little while\u005cn\u0022, bits);\n+\t\t\t\u0022will take a little while\u005cn\u0022, bits);\n \tn \u003d lws_genrsa_new_keypair(vhd-\u003econtext, \u0026vhd-\u003ersactx, LGRSAM_PKCS1_1_5,\n-\t\t\t\t vhd-\u003ejwk.e, bits);\n+\t\t\tvhd-\u003ejwk.e, bits);\n \tif (n) {\n \t\tlwsl_notice(\u0022failed to create keypair\u005cn\u0022);\n-\n \t\treturn 1;\n \t}\n \n \tlwsl_notice(\u0022...keypair generated\u005cn\u0022);\n \n-\tif (lws_jwk_save(\u0026vhd-\u003ejwk,\n-\t\t vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH])) {\n+\tif (lws_jwk_save(\u0026vhd-\u003ejwk, vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH])) {\n \t\tlwsl_notice(\u0022unable to save %s\u005cn\u0022,\n-\t\t vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH]);\n-\n+\t\t\t\tvhd-\u003epvop[LWS_TLS_SET_AUTH_PATH]);\n \t\treturn 1;\n \t}\n \n@@ -467,7 +689,7 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,\n \n static int\n lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,\n-\t\t\t struct lws_vhost *v)\n+\t\tstruct lws_vhost *v)\n {\n \tchar buf[128];\n \n@@ -480,7 +702,7 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,\n \t * ...well... we should try to do something about it then...\n \t */\n \tlwsl_notice(\u0022%s: ACME cert needs creating / updating: \u0022\n-\t\t \u0022vhost %s\u005cn\u0022, __func__, lws_get_vhost_name(vhd-\u003evhost));\n+\t\t\t\u0022vhost %s\u005cn\u0022, __func__, lws_get_vhost_name(vhd-\u003evhost));\n \n \tvhd-\u003eac \u003d malloc(sizeof(*vhd-\u003eac));\n \tmemset(vhd-\u003eac, 0, sizeof(*vhd-\u003eac));\n@@ -504,11 +726,11 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,\n \tif (!vhd-\u003eac-\u003eurls[0][0]) {\n \t\tvhd-\u003eac-\u003estate \u003d ACME_STATE_DIRECTORY;\n \t\tlws_snprintf(buf, sizeof(buf) - 1, \u0022%s\u0022,\n-\t\t\t vhd-\u003epvop_active[LWS_TLS_SET_DIR_URL]);\n+\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_DIR_URL]);\n \t} else {\n-\t\tvhd-\u003eac-\u003estate \u003d ACME_STATE_NEW_REG;\n+\t\tvhd-\u003eac-\u003estate \u003d ACME_STATE_NEW_ACCOUNT;\n \t\tlws_snprintf(buf, sizeof(buf) - 1, \u0022%s\u0022,\n-\t\t\t vhd-\u003eac-\u003eurls[JAD_NEW_REG_URL]);\n+\t\t\t\tvhd-\u003eac-\u003eurls[JAD_NEW_ACCOUNT_URL]);\n \t}\n \n \tvhd-\u003eac-\u003ereal_vh_port \u003d lws_get_vhost_port(vhd-\u003evhost);\n@@ -519,15 +741,15 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,\n \n #if defined(LWS_WITH_ESP32)\n \tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CREATE_KEYS,\n-\t\t\t \u0022Generating keys, please wait\u0022);\n+\t\t\t\u0022Generating keys, please wait\u0022);\n \tif (lws_acme_load_create_auth_keys(vhd, 2048))\n \t\tgoto bail;\n \tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CREATE_KEYS,\n-\t\t\t \u0022Auth keys created\u0022);\n+\t\t\t\u0022Auth keys created\u0022);\n #endif\n \n \tif (lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n-\t\t\t\t \u0026vhd-\u003eac-\u003ecwsi, \u0026vhd-\u003eac-\u003ei, buf, \u0022GET\u0022))\n+\t\t\t\t\u0026vhd-\u003eac-\u003ecwsi, \u0026vhd-\u003eac-\u003ei, buf, \u0022GET\u0022))\n \t\treturn 0;\n \n #if defined(LWS_WITH_ESP32)\n@@ -541,18 +763,17 @@ bail:\n \n static int\n callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n-\t\t void *user, void *in, size_t len)\n+\t\tvoid *user, void *in, size_t len)\n {\n \tstruct per_vhost_data__lws_acme_client *vhd \u003d\n-\t\t\t(struct per_vhost_data__lws_acme_client *)\n-\t\t\tlws_protocol_vh_priv_get(lws_get_vhost(wsi),\n-\t\t\t\t\tlws_get_protocol(wsi));\n+\t\t(struct per_vhost_data__lws_acme_client *)\n+\t\tlws_protocol_vh_priv_get(lws_get_vhost(wsi),\n+\t\t\t\tlws_get_protocol(wsi));\n \tchar buf[LWS_PRE + 2536], *start \u003d buf + LWS_PRE, *p \u003d start,\n-\t *end \u003d buf + sizeof(buf) - 1, digest[32], *failreason \u003d NULL;\n+\t\t *end \u003d buf + sizeof(buf) - 1, digest[32], *failreason \u003d NULL;\n \tconst struct lws_protocol_vhost_options *pvo;\n \tstruct lws_acme_cert_aging_args *caa;\n \tstruct acme_connection *ac \u003d NULL;\n-\tstruct lws_genhash_ctx hctx;\n \tunsigned char **pp, *pend;\n \tconst char *content_type;\n \tstruct lws_jwe jwe;\n@@ -599,15 +820,18 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t}\n \n \t\tn \u003d 0;\n-\t\tfor (m \u003d 0; m \u003c (int)LWS_ARRAY_SIZE(pvo_names); m++)\n-\t\t\tif (!vhd-\u003epvop[m] \u0026\u0026 m \u003e\u003d LWS_TLS_REQ_ELEMENT_COMMON_NAME) {\n+\t\tfor (m \u003d 0; m \u003c (int)LWS_ARRAY_SIZE(pvo_names); m++) {\n+\t\t\tif (!vhd-\u003epvop[m] \u0026\u0026\n+\t\t\t m \u003e\u003d LWS_TLS_REQ_ELEMENT_COMMON_NAME) {\n \t\t\t\tlwsl_notice(\u0022%s: require pvo '%s'\u005cn\u0022, __func__,\n-\t\t\t\t\t\tpvo_names[m]);\n+\t\t\t\t\t pvo_names[m]);\n \t\t\t\tn |\u003d 1;\n-\t\t\t} else\n+\t\t\t} else {\n \t\t\t\tif (vhd-\u003epvop[m])\n \t\t\t\t\tlwsl_info(\u0022 %s: %s\u005cn\u0022, pvo_names[m],\n-\t\t\t\t\t\t\tvhd-\u003epvop[m]);\n+\t\t\t\t\t\t vhd-\u003epvop[m]);\n+\t\t\t}\n+\t\t}\n \t\tif (n) {\n \t\t\tfree(vhd-\u003epvo_data);\n \t\t\tvhd-\u003epvo_data \u003d NULL;\n@@ -628,17 +852,18 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t * still have root\n \t\t */\n \t\tlws_snprintf(buf, sizeof(buf) - 1, \u0022%s.upd\u0022,\n-\t\t\t vhd-\u003epvop[LWS_TLS_SET_CERT_PATH]);\n-\t\tvhd-\u003efd_updated_cert \u003d lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT |\n-\t\t\t\t\t\t LWS_O_TRUNC, 0600);\n+\t\t\t\tvhd-\u003epvop[LWS_TLS_SET_CERT_PATH]);\n+\t\tvhd-\u003efd_updated_cert \u003d lws_open(buf,\n+\t\t\t\t\t\tLWS_O_WRONLY | LWS_O_CREAT |\n+\t\t\t\t\t\tLWS_O_TRUNC, 0600);\n \t\tif (vhd-\u003efd_updated_cert \u003c 0) {\n \t\t\tlwsl_err(\u0022unable to create update cert file %s\u005cn\u0022, buf);\n \t\t\treturn -1;\n \t\t}\n \t\tlws_snprintf(buf, sizeof(buf) - 1, \u0022%s.upd\u0022,\n-\t\t\t vhd-\u003epvop[LWS_TLS_SET_KEY_PATH]);\n+\t\t\t\tvhd-\u003epvop[LWS_TLS_SET_KEY_PATH]);\n \t\tvhd-\u003efd_updated_key \u003d lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT |\n-\t\t\t\t\t\tLWS_O_TRUNC, 0600);\n+\t\t\t\tLWS_O_TRUNC, 0600);\n \t\tif (vhd-\u003efd_updated_key \u003c 0) {\n \t\t\tlwsl_err(\u0022unable to create update key file %s\u005cn\u0022, buf);\n \t\t\treturn -1;\n@@ -682,7 +907,8 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t\t\tvhd-\u003epvop_active[n] \u003d vhd-\u003epvop[n];\n \n \t\tlwsl_notice(\u0022starting acme acquisition on %s: %s\u005cn\u0022,\n-\t\t\t\tlws_get_vhost_name(caa-\u003evh), vhd-\u003epvop_active[LWS_TLS_SET_DIR_URL]);\n+\t\t\t\tlws_get_vhost_name(caa-\u003evh),\n+\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_DIR_URL]);\n \n \t\tlws_acme_start_acquisition(vhd, caa-\u003evh);\n \t\tbreak;\n@@ -708,16 +934,17 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \t\tbreak;\n \n \tcase LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:\n-\t\tlwsl_notice(\u0022lws_http_client_http_response %d\u005cn\u0022,\n-\t\t\t lws_http_client_http_response(wsi));\n+\t\tlwsl_notice(\u0022%s: ESTABLISHED_CLIENT_HTTP:\u0022\n+\t\t\t\t\u0022%p, state:%d, status:%d\u005cn\u0022, __func__, wsi,\n+\t\t\t\tac-\u003estate, lws_http_client_http_response(wsi));\n \t\tif (!ac)\n \t\t\tbreak;\n \t\tac-\u003eresp \u003d lws_http_client_http_response(wsi);\n \t\t/* we get a new nonce each time */\n \t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_REPLAY_NONCE) \u0026\u0026\n-\t\t lws_hdr_copy(wsi, ac-\u003ereplay_nonce,\n-\t\t\t\t sizeof(ac-\u003ereplay_nonce),\n-\t\t\t\t WSI_TOKEN_REPLAY_NONCE) \u003c 0) {\n+\t\t\t\tlws_hdr_copy(wsi, ac-\u003ereplay_nonce,\n+\t\t\t\t\tsizeof(ac-\u003ereplay_nonce),\n+\t\t\t\t\tWSI_TOKEN_REPLAY_NONCE) \u003c 0) {\n \t\t\tlwsl_notice(\u0022%s: nonce too large\u005cn\u0022, __func__);\n \n \t\t\tgoto failed;\n@@ -726,41 +953,80 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \t\tswitch (ac-\u003estate) {\n \t\tcase ACME_STATE_DIRECTORY:\n \t\t\tlejp_construct(\u0026ac-\u003ejctx, cb_dir, vhd, jdir_tok,\n-\t\t\t\t LWS_ARRAY_SIZE(jdir_tok));\n+\t\t\t\t\tLWS_ARRAY_SIZE(jdir_tok));\n+\t\t\tbreak;\n+\t\tcase ACME_STATE_NEW_NONCE:\n+\t\t\t/*\n+\t\t\t * we try to * register our keys next.\n+\t\t\t * It's OK if it ends up * they're already registered,\n+\t\t\t * this eliminates any * gaps where we stored the key\n+\t\t\t * but registration did not complete for some reason...\n+\t\t\t */\n+\t\t\tac-\u003estate \u003d ACME_STATE_NEW_ACCOUNT;\n+\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_REG, NULL);\n+\n+\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_ACCOUNT_URL]);\n+\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n+\t\t\t\t\t\u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf, \u0022POST\u0022);\n+\t\t\tif (!cwsi) {\n+\t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\treturn -1;\n+\n+\t\tcase ACME_STATE_NEW_ACCOUNT:\n+\t\t\tif (!lws_hdr_total_length(wsi,\n+\t\t\t\t\t\t WSI_TOKEN_HTTP_LOCATION)) {\n+\t\t\t\tlwsl_notice(\u0022%s: no Location\u005cn\u0022, __func__);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\tif (lws_hdr_copy(wsi, ac-\u003eacct_id, sizeof(ac-\u003eacct_id),\n+\t\t\t\t\t WSI_TOKEN_HTTP_LOCATION) \u003c 0) {\n+\t\t\t\tlwsl_notice(\u0022%s: Location too large\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\tac-\u003ekid \u003d ac-\u003eacct_id;\n+\n+\t\t\tlwsl_notice(\u0022Location: %s\u005cn\u0022, ac-\u003eacct_id);\n \t\t\tbreak;\n-\t\tcase ACME_STATE_NEW_REG:\n+\n+\t\tcase ACME_STATE_NEW_ORDER:\n+\t\t\tif (lws_hdr_copy(wsi, ac-\u003eorder_url,\n+\t\t\t\t\t sizeof(ac-\u003eorder_url),\n+\t\t\t\t\t WSI_TOKEN_HTTP_LOCATION) \u003c 0) {\n+\t\t\t\tlwsl_notice(\u0022%s: missing cert location:\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n+\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\n+\t\t\tlejp_construct(\u0026ac-\u003ejctx, cb_order, ac, jorder_tok,\n+\t\t\t\t\tLWS_ARRAY_SIZE(jorder_tok));\n \t\t\tbreak;\n-\t\tcase ACME_STATE_NEW_AUTH:\n+\n+\t\tcase ACME_STATE_AUTHZ:\n \t\t\tlejp_construct(\u0026ac-\u003ejctx, cb_authz, ac, jauthz_tok,\n \t\t\t\t\tLWS_ARRAY_SIZE(jauthz_tok));\n \t\t\tbreak;\n \n-\t\tcase ACME_STATE_POLLING:\n-\t\tcase ACME_STATE_ACCEPT_CHALL:\n+\t\tcase ACME_STATE_START_CHALL:\n \t\t\tlejp_construct(\u0026ac-\u003ejctx, cb_chac, ac, jchac_tok,\n \t\t\t\t\tLWS_ARRAY_SIZE(jchac_tok));\n \t\t\tbreak;\n \n+\t\tcase ACME_STATE_POLLING:\n \t\tcase ACME_STATE_POLLING_CSR:\n-\t\t\tac-\u003ecpos \u003d 0;\n-\t\t\tif (ac-\u003eresp !\u003d 201)\n-\t\t\t\tbreak;\n-\t\t\t/*\n-\t\t\t * He acknowledges he will create the cert...\n-\t\t\t * get the URL to GET it from in the Location\n-\t\t\t * header.\n-\t\t\t */\n-\t\t\tif (lws_hdr_copy(wsi, ac-\u003echallenge_uri,\n-\t\t\t\t\t sizeof(ac-\u003echallenge_uri),\n-\t\t\t\t\t WSI_TOKEN_HTTP_LOCATION) \u003c 0) {\n-\t\t\t\tlwsl_notice(\u0022%s: missing cert location:\u005cn\u0022,\n-\t\t\t\t\t __func__);\n-\n-\t\t\t\tgoto failed;\n-\t\t\t}\n+\t\t\tlejp_construct(\u0026ac-\u003ejctx, cb_order, ac, jorder_tok,\n+\t\t\t\t\tLWS_ARRAY_SIZE(jorder_tok));\n+\t\t\tbreak;\n \n-\t\t\tlwsl_notice(\u0022told to fetch cert from %s\u005cn\u0022,\n-\t\t\t\t\tac-\u003echallenge_uri);\n+\t\tcase ACME_STATE_DOWNLOAD_CERT:\n+\t\t\tac-\u003ecpos \u003d 0;\n \t\t\tbreak;\n \n \t\tdefault:\n@@ -771,38 +1037,40 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,\n \tcase LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:\n \t\tif (!ac)\n \t\t\tbreak;\n-\t\tswitch (ac-\u003estate) {\n \n+\t\tswitch (ac-\u003estate) {\n \t\tcase ACME_STATE_DIRECTORY:\n+\t\tcase ACME_STATE_NEW_NONCE:\n \t\t\tbreak;\n-\t\tcase ACME_STATE_NEW_REG:\n+\n+\t\tcase ACME_STATE_NEW_ACCOUNT:\n \t\t\tp +\u003d lws_snprintf(p, end - p, \u0022{\u0022\n-\t\t\t\t\t \u0022\u005c\u0022resource\u005c\u0022:\u005c\u0022new-reg\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022contact\u005c\u0022:[\u0022\n-\t\t\t\t\t \u0022\u005c\u0022mailto:%s\u005c\u0022\u0022\n-\t\t\t\t\t \u0022],\u005c\u0022agreement\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022\n-\t\t\t\t\t \u0022}\u0022,\n-\t\t\t\t\t vhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_EMAIL],\n-\t\t\t\t\t ac-\u003eurls[JAD_TOS_URL]);\n+\t\t\t\t\u0022\u005c\u0022termsOfServiceAgreed\u005c\u0022:true\u0022\n+\t\t\t\t\u0022,\u005c\u0022contact\u005c\u0022: [\u005c\u0022mailto:%s\u005c\u0022]}\u0022,\n+\t\t\t\tvhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_EMAIL]);\n \n \t\t\tputs(start);\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003eurls[JAD_NEW_ACCOUNT_URL]);\n pkt_add_hdrs:\n-\t\t\tif (lws_gencrypto_jwe_alg_to_definition(\u0022RSA1_5\u0022, \u0026jwe.jose.alg)) {\n+\t\t\tif (lws_gencrypto_jwe_alg_to_definition(\u0022RSA1_5\u0022,\n+\t\t\t\t\t\t\u0026jwe.jose.alg)) {\n \t\t\t\tac-\u003elen \u003d 0;\n \t\t\t\tlwsl_notice(\u0022%s: no RSA1_5\u005cn\u0022, __func__);\n \t\t\t\tgoto failed;\n \t\t\t}\n-\t\t\tjwe.jws.jwk \u003d \u0026vhd-\u003ejwk;\n-\t\t\tac-\u003elen \u003d lws_jwe_create_packet(\u0026jwe,\n-\t\t\t\t\t\t\tstart, p - start,\n-\t\t\t\t\t\t\tac-\u003ereplay_nonce,\n-\t\t\t\t\t\t\t\u0026ac-\u003ebuf[LWS_PRE],\n-\t\t\t\t\t\t\tsizeof(ac-\u003ebuf) -\n-\t\t\t\t\t\t\t\t LWS_PRE,\n-\t\t\t\t\t\t\tlws_get_context(wsi));\n+\t\t\tjwe.jwk \u003d vhd-\u003ejwk;\n+\n+\t\t\tac-\u003elen \u003d jws_create_packet(\u0026jwe,\n+\t\t\t\t\tstart, p - start,\n+\t\t\t\t\tac-\u003ereplay_nonce,\n+\t\t\t\t\tac-\u003eactive_url,\n+\t\t\t\t\tac-\u003ekid,\n+\t\t\t\t\t\u0026ac-\u003ebuf[LWS_PRE],\n+\t\t\t\t\tsizeof(ac-\u003ebuf) - LWS_PRE,\n+\t\t\t\t\tlws_get_context(wsi));\n \t\t\tif (ac-\u003elen \u003c 0) {\n \t\t\t\tac-\u003elen \u003d 0;\n-\t\t\t\tlwsl_notice(\u0022lws_jwe_create_packet failed\u005cn\u0022);\n+\t\t\t\tlwsl_notice(\u0022jws_create_packet failed\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n \n@@ -810,156 +1078,70 @@ pkt_add_hdrs:\n \t\t\tpend \u003d (*pp) + len;\n \n \t\t\tac-\u003epos \u003d 0;\n-\t\t\tcontent_type \u003d \u0022application/jose+json\u0022;\n-\t\t\tif (ac-\u003estate \u003d\u003d ACME_STATE_POLLING_CSR)\n-\t\t\t\tcontent_type \u003d \u0022application/pkix-cert\u0022;\n+\t\t\tcontent_type \u003d \u0022application/jose+json\u0022;\n \n \t\t\tif (lws_add_http_header_by_token(wsi,\n-\t\t\t\t WSI_TOKEN_HTTP_CONTENT_TYPE,\n-\t\t\t\t\t(uint8_t *)content_type, 21, pp, pend)) {\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_TYPE,\n+\t\t\t\t\t\t(uint8_t *)content_type, 21, pp,\n+\t\t\t\t\t\tpend)) {\n \t\t\t\tlwsl_notice(\u0022could not add content type\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n \n \t\t\tn \u003d sprintf(buf, \u0022%d\u0022, ac-\u003elen);\n \t\t\tif (lws_add_http_header_by_token(wsi,\n-\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH,\n-\t\t\t\t\t(uint8_t *)buf, n, pp, pend)) {\n+\t\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH,\n+\t\t\t\t\t\t(uint8_t *)buf, n, pp, pend)) {\n \t\t\t\tlwsl_notice(\u0022could not add content length\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n \n \t\t\tlws_client_http_body_pending(wsi, 1);\n \t\t\tlws_callback_on_writable(wsi);\n-\t\t\tlwsl_notice(\u0022prepare to send ACME_STATE_NEW_REG\u005cn\u0022);\n \t\t\tbreak;\n-\t\tcase ACME_STATE_NEW_AUTH:\n+\n+\t\tcase ACME_STATE_NEW_ORDER:\n \t\t\tp +\u003d lws_snprintf(p, end - p,\n \t\t\t\t\t\u0022{\u0022\n-\t\t\t\t\t \u0022\u005c\u0022resource\u005c\u0022:\u005c\u0022new-authz\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022identifier\u005c\u0022:{\u0022\n-\t\t\t\t\t \u0022\u005c\u0022type\u005c\u0022:\u005c\u0022http-01\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022value\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022\n-\t\t\t\t\t \u0022}\u0022\n-\t\t\t\t\t\u0022}\u0022, vhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);\n+\t\t\t\t\t\u0022\u005c\u0022identifiers\u005c\u0022:[{\u0022\n+\t\t\t\t\t\u0022\u005c\u0022type\u005c\u0022:\u005c\u0022dns\u005c\u0022,\u0022\n+\t\t\t\t\t\u0022\u005c\u0022value\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022\n+\t\t\t\t\t\u0022}]\u0022\n+\t\t\t\t\t\u0022}\u0022,\n+\t\t\tvhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);\n+\n+\t\t\tputs(start);\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003eurls[JAD_NEW_ORDER_URL]);\n \t\t\tgoto pkt_add_hdrs;\n \n-\t\tcase ACME_STATE_ACCEPT_CHALL:\n-\t\t\t/*\n-\t\t\t * Several of the challenges in this document makes use\n-\t\t\t * of a key authorization string. A key authorization\n-\t\t\t * expresses a domain holder's authorization for a\n-\t\t\t * specified key to satisfy a specified challenge, by\n-\t\t\t * concatenating the token for the challenge with a key\n-\t\t\t * fingerprint, separated by a \u0022.\u0022 character:\n-\t\t\t *\n-\t\t\t * key-authz \u003d token || '.' ||\n-\t\t\t * \t base64(JWK_Thumbprint(accountKey))\n-\t\t\t *\n-\t\t\t * The \u0022JWK_Thumbprint\u0022 step indicates the computation\n-\t\t\t * specified in [RFC7638], using the SHA-256 digest. As\n-\t\t\t * specified in the individual challenges below, the\n-\t\t\t * token for a challenge is a JSON string comprised\n-\t\t\t * entirely of characters in the base64 alphabet.\n-\t\t\t * The \u0022||\u0022 operator indicates concatenation of strings.\n-\t\t\t *\n-\t\t\t * keyAuthorization (required, string): The key\n-\t\t\t * authorization for this challenge. This value MUST\n-\t\t\t * match the token from the challenge and the client's\n-\t\t\t * account key.\n-\t\t\t *\n-\t\t\t * draft acme-01 tls-sni-01:\n-\t\t\t *\n-\t\t\t * {\n-\t\t\t * \u0022keyAuthorization\u0022: \u0022evaGxfADs...62jcerQ\u0022,\n-\t\t\t * } (Signed as JWS)\n-\t\t\t *\n-\t\t\t * draft acme-07 tls-sni-02:\n-\t\t\t *\n-\t\t\t * POST /acme/authz/1234/1\n-\t\t\t * Host: example.com\n-\t\t\t * Content-Type: application/jose+json\n-\t\t\t *\n-\t\t\t * {\n-\t\t\t * \u0022protected\u0022: base64url({\n-\t\t\t * \u0022alg\u0022: \u0022ES256\u0022,\n-\t\t\t * \u0022kid\u0022: \u0022https://example.com/acme/acct/1\u0022,\n-\t\t\t * \u0022nonce\u0022: \u0022JHb54aT_KTXBWQOzGYkt9A\u0022,\n-\t\t\t * \u0022url\u0022: \u0022https://example.com/acme/authz/1234/1\u0022\n-\t\t\t * }),\n-\t\t\t * \u0022payload\u0022: base64url({\n-\t\t\t * \u0022keyAuthorization\u0022: \u0022evaGxfADs...62jcerQ\u0022\n-\t\t\t * }),\n-\t\t\t * \u0022signature\u0022: \u0022Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4\u0022\n-\t\t\t * }\n-\t\t\t *\n-\t\t\t * On receiving a response, the server MUST verify that\n-\t\t\t * the key authorization in the response matches the\n-\t\t\t * \u0022token\u0022 value in the challenge and the client's\n-\t\t\t * account key. If they do not match, then the server\n-\t\t\t * MUST return an HTTP error in response to the POST\n-\t\t\t * request in which the client sent the challenge.\n-\t\t\t */\n+\t\tcase ACME_STATE_AUTHZ:\n+\t\t\tputs(start);\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003eauthz_url);\n+\t\t\tgoto pkt_add_hdrs;\n \n-\t\t\tlws_jwk_rfc7638_fingerprint(\u0026vhd-\u003ejwk, digest);\n+\t\tcase ACME_STATE_START_CHALL:\n \t\t\tp \u003d start;\n \t\t\tend \u003d \u0026buf[sizeof(buf) - 1];\n \n-\t\t\tp +\u003d lws_snprintf(p, end - p,\n-\t\t\t\t\t \u0022{\u005c\u0022resource\u005c\u0022:\u005c\u0022challenge\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022type\u005c\u0022:\u005c\u0022tls-sni-0%d\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022keyAuthorization\u005c\u0022:\u005c\u0022%s.\u0022,\n-\t\t\t\t\t 1 + ac-\u003eis_sni_02,\n-\t\t\t\t\t ac-\u003echall_token);\n-\t\t\tn \u003d lws_jws_base64_enc(digest, 32, p, end - p);\n-\t\t\tif (n \u003c 0)\n-\t\t\t\tgoto failed;\n-\t\t\tp +\u003d n;\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022}\u0022);\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022{}\u0022);\n \t\t\tputs(start);\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003echallenge_uri);\n \t\t\tgoto pkt_add_hdrs;\n \n \t\tcase ACME_STATE_POLLING:\n-\t\t\tbreak;\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003eorder_url);\n+\t\t\tgoto pkt_add_hdrs;\n \n \t\tcase ACME_STATE_POLLING_CSR:\n-\t\t\t/*\n-\t\t\t * \u0022To obtain a certificate for the domain, the agent\n-\t\t\t * constructs a PKCS#10 Certificate Signing Request that\n-\t\t\t * asks the Let’s Encrypt CA to issue a certificate for\n-\t\t\t * example.com with a specified public key. As usual,\n-\t\t\t * the CSR includes a signature by the private key\n-\t\t\t * corresponding to the public key in the CSR. The agent\n-\t\t\t * also signs the whole CSR with the authorized\n-\t\t\t * key for example.com so that the Let’s Encrypt CA\n-\t\t\t * knows it’s authorized.\u0022\n-\t\t\t *\n-\t\t\t * IOW we must create a new RSA keypair which will be\n-\t\t\t * the cert public + private key, and put the public\n-\t\t\t * key in the CSR. The CSR, just for transport, is also\n-\t\t\t * signed with our JWK, showing that as the owner of the\n-\t\t\t * authorized JWK, the request should be allowed.\n-\t\t\t *\n-\t\t\t * The cert comes back with our public key in it showing\n-\t\t\t * that the owner of the matching private key (we\n-\t\t\t * created that keypair) is the owner of the cert.\n-\t\t\t *\n-\t\t\t * We feed the CSR the elements we want in the cert,\n-\t\t\t * like the CN etc, and it gives us the b64URL-encoded\n-\t\t\t * CSR and the PEM-encoded (public +)private key in\n-\t\t\t * memory buffers.\n-\t\t\t */\n \t\t\tif (ac-\u003egoes_around)\n \t\t\t\tbreak;\n \n-\t\t\tp +\u003d lws_snprintf(p, end - p,\n-\t\t\t\t\t \u0022{\u005c\u0022resource\u005c\u0022:\u005c\u0022new-cert\u005c\u0022,\u0022\n-\t\t\t\t\t \u0022\u005c\u0022csr\u005c\u0022:\u005c\u0022\u0022);\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022{\u005c\u0022csr\u005c\u0022:\u005c\u0022\u0022);\n \t\t\tn \u003d lws_tls_acme_sni_csr_create(vhd-\u003econtext,\n-\t\t\t\t\t\t\t\u0026vhd-\u003epvop_active[0],\n-\t\t\t\t\t\t\t(uint8_t *)p, end - p,\n-\t\t\t\t\t\t\t\u0026ac-\u003ealloc_privkey_pem,\n-\t\t\t\t\t\t\t\u0026ac-\u003elen_privkey_pem);\n+\t\t\t\t\t\u0026vhd-\u003epvop_active[0],\n+\t\t\t\t\t(uint8_t *)p, end - p,\n+\t\t\t\t\t\u0026ac-\u003ealloc_privkey_pem,\n+\t\t\t\t\t\u0026ac-\u003elen_privkey_pem);\n \t\t\tif (n \u003c 0) {\n \t\t\t\tlwsl_notice(\u0022CSR generation failed\u005cn\u0022);\n \t\t\t\tgoto failed;\n@@ -967,8 +1149,14 @@ pkt_add_hdrs:\n \t\t\tp +\u003d n;\n \t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022}\u0022);\n \t\t\tputs(start);\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003efinalize_url);\n \t\t\tgoto pkt_add_hdrs;\n \n+\t\tcase ACME_STATE_DOWNLOAD_CERT:\n+\t\t\tstrcpy(ac-\u003eactive_url, ac-\u003ecert_url);\n+\t\t\tgoto pkt_add_hdrs;\n+\t\t\tbreak;\n+\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -976,14 +1164,16 @@ pkt_add_hdrs:\n \n \tcase LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:\n \t\tlwsl_notice(\u0022LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\u005cn\u0022);\n+\n \t\tif (!ac)\n \t\t\tbreak;\n+\n \t\tif (ac-\u003epos \u003d\u003d ac-\u003elen)\n \t\t\tbreak;\n \n \t\tac-\u003ebuf[LWS_PRE + ac-\u003elen] \u003d '\u005c0';\n \t\tif (lws_write(wsi, (uint8_t *)ac-\u003ebuf + LWS_PRE,\n-\t\t\t ac-\u003elen, LWS_WRITE_HTTP_FINAL) \u003c 0)\n+\t\t\t\t\tac-\u003elen, LWS_WRITE_HTTP_FINAL) \u003c 0)\n \t\t\treturn -1;\n \t\tlwsl_notice(\u0022wrote %d\u005cn\u0022, ac-\u003elen);\n \t\tac-\u003epos \u003d ac-\u003elen;\n@@ -994,25 +1184,30 @@ pkt_add_hdrs:\n \tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:\n \t\tif (!ac)\n \t\t\treturn -1;\n+\n \t\tswitch (ac-\u003estate) {\n+\t\tcase ACME_STATE_POLLING_CSR:\n \t\tcase ACME_STATE_POLLING:\n-\t\tcase ACME_STATE_ACCEPT_CHALL:\n-\t\tcase ACME_STATE_NEW_AUTH:\n+\t\tcase ACME_STATE_START_CHALL:\n+\t\tcase ACME_STATE_AUTHZ:\n+\t\tcase ACME_STATE_NEW_ORDER:\n \t\tcase ACME_STATE_DIRECTORY:\n \t\t\t((char *)in)[len] \u003d '\u005c0';\n \t\t\tputs(in);\n \t\t\tm \u003d (int)(signed char)lejp_parse(\u0026ac-\u003ejctx,\n-\t\t\t\t\t\t\t (uint8_t *)in, len);\n+\t\t\t\t\t(uint8_t *)in, len);\n \t\t\tif (m \u003c 0 \u0026\u0026 m !\u003d LEJP_CONTINUE) {\n \t\t\t\tlwsl_notice(\u0022lejp parse failed %d\u005cn\u0022, m);\n \t\t\t\tgoto failed;\n \t\t\t}\n \t\t\tbreak;\n-\t\tcase ACME_STATE_NEW_REG:\n+\t\tcase ACME_STATE_NEW_ACCOUNT:\n \t\t\t((char *)in)[len] \u003d '\u005c0';\n \t\t\tputs(in);\n \t\t\tbreak;\n-\t\tcase ACME_STATE_POLLING_CSR:\n+\t\tcase ACME_STATE_DOWNLOAD_CERT:\n+\t\t\t((char *)in)[len] \u003d '\u005c0';\n+\t\t\tputs(in);\n \t\t\t/* it should be the DER cert! */\n \t\t\tif (ac-\u003ecpos + len \u003e sizeof(ac-\u003ebuf)) {\n \t\t\t\tlwsl_notice(\u0022Incoming cert is too large!\u005cn\u0022);\n@@ -1029,13 +1224,19 @@ pkt_add_hdrs:\n \t/* unchunked content */\n \tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP:\n \t\tlwsl_notice(\u0022%s: LWS_CALLBACK_RECEIVE_CLIENT_HTTP\u005cn\u0022, __func__);\n-\t\t{\n-\t\t\tchar buffer[2048 + LWS_PRE];\n-\t\t\tchar *px \u003d buffer + LWS_PRE;\n-\t\t\tint lenx \u003d sizeof(buffer) - LWS_PRE;\n+\t\tif (!ac)\n+\t\t\treturn -1;\n+\t\tswitch (ac-\u003estate) {\n+\t\tdefault:\n+\t\t\t{\n+\t\t\t\tchar buffer[2048 + LWS_PRE];\n+\t\t\t\tchar *px \u003d buffer + LWS_PRE;\n+\t\t\t\tint lenx \u003d sizeof(buffer) - LWS_PRE;\n \n-\t\t\tif (lws_http_client_read(wsi, \u0026px, \u0026lenx) \u003c 0)\n-\t\t\t\treturn -1;\n+\t\t\t\tif (lws_http_client_read(wsi, \u0026px, \u0026lenx) \u003c 0)\n+\t\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tbreak;\n \t\t}\n \t\tbreak;\n \n@@ -1044,6 +1245,7 @@ pkt_add_hdrs:\n \n \t\tif (!ac)\n \t\t\treturn -1;\n+\n \t\tswitch (ac-\u003estate) {\n \t\tcase ACME_STATE_DIRECTORY:\n \t\t\tlejp_destruct(\u0026ac-\u003ejctx);\n@@ -1053,212 +1255,125 @@ pkt_add_hdrs:\n \t\t\tfor (n \u003d 0; n \u003c 6; n++)\n \t\t\t\tlwsl_notice(\u0022 %d: %s\u005cn\u0022, n, ac-\u003eurls[n]);\n \n-\t\t\t/*\n-\t\t\t * So... having the directory now... we try to\n-\t\t\t * register our keys next. It's OK if it ends up\n-\t\t\t * they're already registered... this eliminates any\n-\t\t\t * gaps where we stored the key but registration did\n-\t\t\t * not complete for some reason...\n-\t\t\t */\n-\t\t\tac-\u003estate \u003d ACME_STATE_NEW_REG;\n-\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_REG, NULL);\n+\t\t\tac-\u003estate \u003d ACME_STATE_NEW_NONCE;\n \n-\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_REG_URL]);\n+\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_NONCE_URL]);\n \t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n-\t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n-\t\t\t\t\t\t \u0022POST\u0022);\n+\t\t\t\t\t\u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n+\t\t\t\t\t\u0022GET\u0022);\n \t\t\tif (!cwsi) {\n \t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\t\t\t\t__func__);\n \t\t\t\tgoto failed;\n \t\t\t}\n \t\t\treturn -1; /* close the completed client connection */\n \n-\t\tcase ACME_STATE_NEW_REG:\n+\t\tcase ACME_STATE_NEW_ACCOUNT:\n \t\t\tif ((ac-\u003eresp \u003e\u003d 200 \u0026\u0026 ac-\u003eresp \u003c 299) ||\n-\t\t\t ac-\u003eresp \u003d\u003d 409) {\n+\t\t\t\t\tac-\u003eresp \u003d\u003d 409) {\n \t\t\t\t/*\n \t\t\t\t * Our account already existed, or exists now.\n \t\t\t\t *\n-\t\t\t\t * Move on to requesting a cert auth.\n \t\t\t\t */\n-\t\t\t\tac-\u003estate \u003d ACME_STATE_NEW_AUTH;\n-\t\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_AUTH,\n-\t\t\t\t\t\t\tNULL);\n+\t\t\t\tac-\u003estate \u003d ACME_STATE_NEW_ORDER;\n \n-\t\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_AUTHZ_URL]);\n+\t\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_ORDER_URL]);\n \t\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext,\n-\t\t\t\t\t\t\tvhd-\u003evhost, \u0026ac-\u003ecwsi,\n-\t\t\t\t\t\t\t\u0026ac-\u003ei, buf, \u0022POST\u0022);\n+\t\t\t\t\t\tvhd-\u003evhost, \u0026ac-\u003ecwsi,\n+\t\t\t\t\t\t\u0026ac-\u003ei, buf, \u0022POST\u0022);\n \t\t\t\tif (!cwsi)\n \t\t\t\t\tlwsl_notice(\u0022%s: failed to connect\u005cn\u0022,\n-\t\t\t\t\t\t __func__);\n-\t\t\t\treturn -1; /* close the completed client connection */\n+\t\t\t\t\t\t\t__func__);\n+\n+\t\t\t\t/* close the completed client connection */\n+\t\t\t\treturn -1;\n \t\t\t} else {\n-\t\t\t\tlwsl_notice(\u0022new-reg replied %d\u005cn\u0022, ac-\u003eresp);\n+\t\t\t\tlwsl_notice(\u0022newAccount replied %d\u005cn\u0022,\n+\t\t\t\t\t\tac-\u003eresp);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\t\t\treturn -1; /* close the completed client connection */\n+\n+\t\tcase ACME_STATE_NEW_ORDER:\n+\t\t\tlejp_destruct(\u0026ac-\u003ejctx);\n+\t\t\tif (!ac-\u003eauthz_url[0]) {\n+\t\t\t\tlwsl_notice(\u0022no authz\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * Move on to requesting a cert auth.\n+\t\t\t */\n+\t\t\tac-\u003estate \u003d ACME_STATE_AUTHZ;\n+\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_AUTH,\n+\t\t\t\t\tNULL);\n+\n+\t\t\tstrcpy(buf, ac-\u003eauthz_url);\n+\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext,\n+\t\t\t\t\tvhd-\u003evhost, \u0026ac-\u003ecwsi,\n+\t\t\t\t\t\u0026ac-\u003ei, buf, \u0022POST\u0022);\n+\t\t\tif (!cwsi)\n+\t\t\t\tlwsl_notice(\u0022%s: failed to connect\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n+\n \t\t\treturn -1; /* close the completed client connection */\n \n-\t\tcase ACME_STATE_NEW_AUTH:\n+\t\tcase ACME_STATE_AUTHZ:\n \t\t\tlejp_destruct(\u0026ac-\u003ejctx);\n \t\t\tif (ac-\u003eresp / 100 \u003d\u003d 4) {\n \t\t\t\tlws_snprintf(buf, sizeof(buf),\n-\t\t\t\t\t \u0022Auth failed: %s\u0022, ac-\u003edetail);\n+\t\t\t\t\t\t\u0022Auth failed: %s\u0022, ac-\u003edetail);\n \t\t\t\tfailreason \u003d buf;\n \t\t\t\tlwsl_notice(\u0022auth failed\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n-\t\t\tlwsl_notice(\u0022chall: %s (%d)\u005cn\u0022, ac-\u003echall_token, ac-\u003eresp);\n+\t\t\tlwsl_notice(\u0022chall: %s (%d)\u005cn\u0022, ac-\u003echall_token,\n+\t\t\t\t\tac-\u003eresp);\n \t\t\tif (!ac-\u003echall_token[0]) {\n \t\t\t\tlwsl_notice(\u0022no challenge\u005cn\u0022);\n \t\t\t\tgoto failed;\n \t\t\t}\n \n-\n-\t\t\tac-\u003estate \u003d ACME_STATE_ACCEPT_CHALL;\n+\t\t\tac-\u003estate \u003d ACME_STATE_START_CHALL;\n \t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CHALLENGE,\n-\t\t\t\t\t\tNULL);\n-\n-\t\t\t/* tls-sni-01 ... what a mess.\n-\t\t\t * The stuff in\n-\t\t\t * https://tools.ietf.org/html/\n-\t\t\t * \t\tdraft-ietf-acme-acme-01#section-7.3\n-\t\t\t * \u0022requires\u0022 n but it's missing from let's encrypt\n-\t\t\t * tls-sni-01 challenge. The go docs say that they just\n-\t\t\t * implement one hashing round regardless\n-\t\t\t * https://godoc.org/golang.org/x/crypto/acme\n-\t\t\t *\n-\t\t\t * The go way is what is actually implemented today by\n-\t\t\t * letsencrypt\n-\t\t\t *\n-\t\t\t * \u0022A client responds to this challenge by constructing\n-\t\t\t * a key authorization from the \u0022token\u0022 value provided\n-\t\t\t * in the challenge and the client's account key. The\n-\t\t\t * client first computes the SHA-256 digest Z0 of the\n-\t\t\t * UTF8-encoded key authorization, and encodes Z0 in\n-\t\t\t * UTF-8 lower-case hexadecimal form.\u0022\n-\t\t\t */\n-\n-\t\t\t/* tls-sni-02\n-\t\t\t *\n-\t\t\t * SAN A MUST be constructed as follows: compute the\n-\t\t\t * SHA-256 digest of the UTF-8-encoded challenge token\n-\t\t\t * and encode it in lowercase hexadecimal form. The\n-\t\t\t * dNSName is \u0022x.y.token.acme.invalid\u0022, where x\n-\t\t\t * is the first half of the hexadecimal representation\n-\t\t\t * and y is the second half.\n-\t\t\t */\n+\t\t\t\t\tNULL);\n \n \t\t\tmemset(\u0026ac-\u003eci, 0, sizeof(ac-\u003eci));\n \n-\t\t\t/* first compute the key authorization */\n+\t\t\t/* compute the key authorization */\n \n-\t\t\tlws_jwk_rfc7638_fingerprint(\u0026vhd-\u003ejwk, digest);\n-\t\t\tp \u003d start;\n-\t\t\tend \u003d \u0026buf[sizeof(buf) - 1];\n+\t\t\tp \u003d ac-\u003ekey_auth;\n+\t\t\tend \u003d p + sizeof(ac-\u003ekey_auth) - 1;\n \n \t\t\tp +\u003d lws_snprintf(p, end - p, \u0022%s.\u0022, ac-\u003echall_token);\n+\t\t\tlws_jwk_rfc7638_fingerprint(\u0026vhd-\u003ejwk, digest);\n \t\t\tn \u003d lws_jws_base64_enc(digest, 32, p, end - p);\n \t\t\tif (n \u003c 0)\n \t\t\t\tgoto failed;\n-\t\t\tp +\u003d n;\n \n-\t\t\tif (lws_genhash_init(\u0026hctx, LWS_GENHASH_TYPE_SHA256))\n-\t\t\t\treturn -1;\n+\t\t\tlwsl_notice(\u0022key_auth: '%s'\u005cn\u0022, ac-\u003ekey_auth);\n \n-\t\t\tif (lws_genhash_update(\u0026hctx, (uint8_t *)start,\n-\t\t\t\t\t\tlws_ptr_diff(p, start))) {\n-\t\t\t\tlws_genhash_destroy(\u0026hctx, NULL);\n+\t\t\tlws_snprintf(ac-\u003ehttp01_mountpoint,\n+\t\t\t\t\tsizeof(ac-\u003ehttp01_mountpoint),\n+\t\t\t\t\t\u0022/.well-known/acme-challenge/%s\u0022,\n+\t\t\t\t\tac-\u003echall_token);\n \n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tif (lws_genhash_destroy(\u0026hctx, digest))\n-\t\t\t\treturn -1;\n-\n-\t\t\tp \u003d buf;\n-\t\t\tfor (n \u003d 0; n \u003c 32; n++) {\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022%02x\u0022,\n-\t\t\t\t\t\t digest[n] \u0026 0xff);\n-\t\t\t\tif (n \u003d\u003d (32 / 2) - 1)\n-\t\t\t\t\tp \u003d buf + 64;\n-\t\t\t}\n+\t\t\tmemset(\u0026ac-\u003emount, 0, sizeof (struct lws_http_mount));\n+\t\t\tac-\u003emount.protocol \u003d \u0022http\u0022;\n+\t\t\tac-\u003emount.mountpoint \u003d ac-\u003ehttp01_mountpoint;\n+\t\t\tac-\u003emount.mountpoint_len \u003d\n+\t\t\t\tstrlen(ac-\u003ehttp01_mountpoint);\n+\t\t\tac-\u003emount.origin_protocol \u003d LWSMPRO_CALLBACK;\n \n-\t\t\tp \u003d ac-\u003esan_a;\n-\t\t\tif (ac-\u003eis_sni_02) {\n-\t\t\t\tlws_snprintf(p, sizeof(ac-\u003esan_a),\n-\t\t\t\t\t \u0022%s.%s.token.acme.invalid\u0022,\n-\t\t\t\t\t buf, buf + 64);\n-\n-\t\t\t\t/*\n-\t\t\t\t * SAN B MUST be constructed as follows: compute\n-\t\t\t\t * the SHA-256 digest of the UTF-8 encoded key\n-\t\t\t\t * authorization and encode it in lowercase\n-\t\t\t\t * hexadecimal form. The dNSName is\n-\t\t\t\t * \u0022x.y.ka.acme.invalid\u0022 where x is the first\n-\t\t\t\t * half of the hexadecimal representation and y\n-\t\t\t\t * is the second half.\n-\t\t\t\t */\n-\t\t\t\tlws_jwk_rfc7638_fingerprint(\u0026vhd-\u003ejwk,\n-\t\t\t\t\t\t\t (char *)digest);\n-\n-\t\t\t\tp \u003d buf;\n-\t\t\t\tfor (n \u003d 0; n \u003c 32; n++) {\n-\t\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022%02x\u0022,\n-\t\t\t\t\t\t\t digest[n] \u0026 0xff);\n-\t\t\t\t\tif (n \u003d\u003d (32 / 2) - 1)\n-\t\t\t\t\t\tp \u003d buf + 64;\n-\t\t\t\t}\n-\n-\t\t\t\tp \u003d ac-\u003esan_b;\n-\t\t\t\tlws_snprintf(p, sizeof(ac-\u003esan_b),\n-\t\t\t\t\t \u0022%s.%s.ka.acme.invalid\u0022,\n-\t\t\t\t\t buf, buf + 64);\n-\t\t\t} else {\n-\t\t\t\tlws_snprintf(p, sizeof(ac-\u003esan_a),\n-\t\t\t\t \u0022%s.%s.acme.invalid\u0022, buf, buf + 64);\n-\t\t\t\tac-\u003esan_b[0] \u003d '\u005c0';\n-\t\t\t}\n-\n-\t\t\tlwsl_notice(\u0022san_a: '%s'\u005cn\u0022, ac-\u003esan_a);\n-\t\t\tlwsl_notice(\u0022san_b: '%s'\u005cn\u0022, ac-\u003esan_b);\n-\n-\t\t\t/*\n-\t\t\t * tls-sni-01:\n-\t\t\t *\n-\t\t\t * The client then configures the TLS server at the\n-\t\t\t * domain such that when a handshake is initiated with\n-\t\t\t * the Server Name Indication extension set to\n-\t\t\t * \u0022\u003cZi[0:32]\u003e.\u003cZi[32:64]\u003e.acme.invalid\u0022, the\n-\t\t\t * corresponding generated certificate is presented.\n-\t\t\t *\n-\t\t\t * tls-sni-02:\n-\t\t\t *\n-\t\t\t * The client MUST ensure that the certificate is\n-\t\t\t * served to TLS connections specifying a Server Name\n-\t\t\t * Indication (SNI) value of SAN A.\n-\t\t\t */\n-\t\t\tac-\u003eci.vhost_name \u003d ac-\u003esan_a;\n-\n-\t\t\t/*\n-\t\t\t * we bind to exact iface of real vhost, so we can\n-\t\t\t * share the listen socket by SNI\n-\t\t\t */\n-\t\t\tac-\u003eci.iface \u003d ac-\u003ereal_vh_iface;\n+\t\t\tac-\u003eci.mounts \u003d \u0026ac-\u003emount;\n \n \t\t\t/* listen on the same port as the vhost that triggered\n \t\t\t * us */\n-\t\t\tac-\u003eci.port \u003d ac-\u003ereal_vh_port;\n-\t\t\t/* Skip filling in any x509 info into the ssl_ctx.\n-\t\t\t * It will be done at the callback\n-\t\t\t * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\n-\t\t\t * in this callback handler (below)\n-\t\t\t */\n-\t\t\tac-\u003eci.options \u003d LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |\n-\t\t\t\t\t LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT |\n-\t\t\t\t\t LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n+\t\t\tac-\u003eci.port \u003d 80;\n+\n \t\t\t/* make ourselves protocols[0] for the new vhost */\n-\t\t\tac-\u003eci.protocols \u003d acme_protocols;\n+\t\t\tac-\u003eci.protocols \u003d chall_http01_protocols;\n+\n \t\t\t/*\n \t\t\t * vhost .user points to the ac associated with the\n \t\t\t * temporary vhost\n@@ -1266,75 +1381,72 @@ pkt_add_hdrs:\n \t\t\tac-\u003eci.user \u003d ac;\n \n \t\t\tac-\u003evhost \u003d lws_create_vhost(lws_get_context(wsi),\n-\t\t\t\t\t\t \u0026ac-\u003eci);\n+\t\t\t\t\t\u0026ac-\u003eci);\n \t\t\tif (!ac-\u003evhost)\n \t\t\t\tgoto failed;\n \n+\t\t\tlwsl_notice(\u0022challenge_uri %s\u005cn\u0022, ac-\u003echallenge_uri);\n+\n \t\t\t/*\n \t\t\t * The challenge-specific vhost is up... let the ACME\n \t\t\t * server know we are ready to roll...\n \t\t\t */\n-\n \t\t\tac-\u003egoes_around \u003d 0;\n \t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n \t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei,\n \t\t\t\t\t\t ac-\u003echallenge_uri,\n \t\t\t\t\t\t \u0022POST\u0022);\n \t\t\tif (!cwsi) {\n-\t\t\t\tlwsl_notice(\u0022%s: failed to connect\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\t\tlwsl_notice(\u0022%s: connect failed\u005cn\u0022, __func__);\n \t\t\t\tgoto failed;\n \t\t\t}\n \t\t\treturn -1; /* close the completed client connection */\n \n-\t\tcase ACME_STATE_ACCEPT_CHALL:\n-\t\t\t/*\n-\t\t\t * he returned something like this (which we parsed)\n-\t\t\t *\n-\t\t\t * {\n-\t\t\t * \u0022type\u0022: \u0022tls-sni-01\u0022,\n-\t\t\t * \u0022status\u0022: \u0022pending\u0022,\n-\t\t\t * \u0022uri\u0022: \u0022https://acme-staging.api.letsencrypt.org/\n-\t\t\t * \t\tacme/challenge/xCt7bT3FaxoIQU3Qry87t5h\n-\t\t\t * \t\tuKDcC-L-0ERcD5DLAZts/71100507\u0022,\n-\t\t\t * \u0022token\u0022: \u0022j2Vs-vLI_dsza4A35SFHIU03aIe2PzFRijbqCY\n-\t\t\t * \t\tdIVeE\u0022,\n-\t\t\t * \u0022keyAuthorization\u0022: \u0022j2Vs-vLI_dsza4A35SFHIU03aIe2\n-\t\t\t * \t\tPzFRijbqCYdIVeE.nmOtdFd8Jikn6K8NnYYmT5\n-\t\t\t * \t\tvCM_PwSDT8nLdOYoFXhRU\u0022\n-\t\t\t * }\n-\t\t\t *\n-\t\t\t */\n-\t\t\tlwsl_notice(\u0022%s: COMPLETED accept chall: %s\u005cn\u0022,\n-\t\t\t\t\t__func__, ac-\u003echallenge_uri);\n+\t\tcase ACME_STATE_START_CHALL:\n+\t\t\tlwsl_notice(\u0022%s: COMPLETED start chall: %s\u005cn\u0022,\n+\t\t\t\t __func__, ac-\u003echallenge_uri);\n poll_again:\n \t\t\tac-\u003estate \u003d ACME_STATE_POLLING;\n-\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CHALLENGE, NULL);\n+\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CHALLENGE,\n+\t\t\t\t\t NULL);\n \n \t\t\tif (ac-\u003egoes_around++ \u003d\u003d 20) {\n \t\t\t\tlwsl_notice(\u0022%s: too many chall retries\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\t\t\t\t__func__);\n \n \t\t\t\tgoto failed;\n \t\t\t}\n \n-\t\t\tlws_timed_callback_vh_protocol(vhd-\u003evhost, vhd-\u003eprotocol,\n-\t\t\t\t\tLWS_CALLBACK_USER + 0xac33, ac-\u003egoes_around \u003d\u003d 1 ? 10 : 2);\n+\t\t\tstrcpy(buf, ac-\u003eorder_url);\n+\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n+\t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n+\t\t\t\t\t\t \u0022POST\u0022);\n+\t\t\tif (!cwsi) {\n+\t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n+\n+\t\t\t\tgoto failed;\n+\t\t\t}\n \t\t\treturn -1; /* close the completed client connection */\n \n \t\tcase ACME_STATE_POLLING:\n \n-\t\t\tif (ac-\u003eresp \u003d\u003d 202 \u0026\u0026\n-\t\t\t strcmp(ac-\u003estatus, \u0022invalid\u0022) \u0026\u0026\n-\t\t\t strcmp(ac-\u003estatus, \u0022valid\u0022)) {\n+\t\t\tif (ac-\u003eresp \u003d\u003d 202 \u0026\u0026 strcmp(ac-\u003estatus, \u0022invalid\u0022) \u0026\u0026\n+\t\t\t\t\t strcmp(ac-\u003estatus, \u0022valid\u0022)) {\n+\t\t\t\tlwsl_notice(\u0022status: %s\u005cn\u0022, ac-\u003estatus);\n+\t\t\t\tgoto poll_again;\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(ac-\u003estatus, \u0022pending\u0022)) {\n \t\t\t\tlwsl_notice(\u0022status: %s\u005cn\u0022, ac-\u003estatus);\n \t\t\t\tgoto poll_again;\n \t\t\t}\n \n \t\t\tif (!strcmp(ac-\u003estatus, \u0022invalid\u0022)) {\n-\t\t\t\tlwsl_notice(\u0022%s: polling failed\u005cn\u0022, __func__);\n+\t\t\t\tlwsl_notice(\u0022%s: Challenge failed\u005cn\u0022, __func__);\n \t\t\t\tlws_snprintf(buf, sizeof(buf),\n-\t\t\t\t\t \u0022Challenge Invalid: %s\u0022, ac-\u003edetail);\n+\t\t\t\t\t\t\u0022Challenge Invalid: %s\u0022,\n+\t\t\t\t\t\tac-\u003edetail);\n \t\t\t\tfailreason \u003d buf;\n \t\t\t\tgoto failed;\n \t\t\t}\n@@ -1343,7 +1455,7 @@ poll_again:\n \n \t\t\t/*\n \t\t\t * The challenge was validated... so delete the\n-\t\t\t * temp SNI vhost now its job is done\n+\t\t\t * temp vhost now its job is done\n \t\t\t */\n \t\t\tif (ac-\u003evhost)\n \t\t\t\tlws_vhost_destroy(ac-\u003evhost);\n@@ -1359,224 +1471,141 @@ poll_again:\n \t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_REQ, NULL);\n \t\t\tac-\u003egoes_around \u003d 0;\n \n-\t\t\tstrcpy(buf, ac-\u003eurls[JAD_NEW_CERT_URL]);\n+\t\t\tstrcpy(buf, ac-\u003efinalize_url);\n \t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n \t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n \t\t\t\t\t\t \u0022POST\u0022);\n \t\t\tif (!cwsi) {\n \t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\t\t\t\t__func__);\n \n \t\t\t\tgoto failed;\n \t\t\t}\n \t\t\treturn -1; /* close the completed client connection */\n \n \t\tcase ACME_STATE_POLLING_CSR:\n-\t\t\t/*\n-\t\t\t * (after POSTing the CSR)...\n-\t\t\t *\n-\t\t\t * If the CA decides to issue a certificate, then the\n-\t\t\t * server creates a new certificate resource and\n-\t\t\t * returns a URI for it in the Location header field\n-\t\t\t * of a 201 (Created) response.\n-\t\t\t *\n-\t\t\t * HTTP/1.1 201 Created\n-\t\t\t * Location: https://example.com/acme/cert/asdf\n-\t\t\t *\n-\t\t\t * If the certificate is available at the time of the\n-\t\t\t * response, it is provided in the body of the response.\n-\t\t\t * If the CA has not yet issued the certificate, the\n-\t\t\t * body of this response will be empty. The client\n-\t\t\t * should then send a GET request to the certificate URI\n-\t\t\t * to poll for the certificate. As long as the\n-\t\t\t * certificate is unavailable, the server MUST provide a\n-\t\t\t * 202 (Accepted) response and include a Retry-After\n-\t\t\t * header to indicate when the server believes the\n-\t\t\t * certificate will be issued.\n-\t\t\t */\n \t\t\tif (ac-\u003eresp \u003c 200 || ac-\u003eresp \u003e 202) {\n \t\t\t\tlwsl_notice(\u0022CSR poll failed on resp %d\u005cn\u0022,\n-\t\t\t\t\t ac-\u003eresp);\n+\t\t\t\t\t\tac-\u003eresp);\n \t\t\t\tgoto failed;\n \t\t\t}\n \n-\t\t\tif (ac-\u003eresp \u003d\u003d 200) {\n-\t\t\t\tchar *pp;\n-\t\t\t\tint max;\n-\n-\t\t\t\tlwsl_notice(\u0022The cert was sent..\u005cn\u0022);\n-\n-\t\t\t\tlws_acme_report_status(vhd-\u003evhost,\n-\t\t\t\t\t\tLWS_CUS_ISSUE, NULL);\n+\t\t\tif (ac-\u003eresp !\u003d 200) {\n+\t\t\t\tif (ac-\u003egoes_around++ \u003d\u003d 30) {\n+\t\t\t\t\tlwsl_notice(\u0022%s: too many retries\u005cn\u0022,\n+\t\t\t\t\t\t\t__func__);\n \n-\t\t\t\t/*\n-\t\t\t\t * That means we have the issued cert DER in\n-\t\t\t\t * ac-\u003ebuf, length in ac-\u003ecpos; and the key in\n-\t\t\t\t * ac-\u003ealloc_privkey_pem, length in\n-\t\t\t\t * ac-\u003elen_privkey_pem.\n-\t\t\t\t *\n-\t\t\t\t * We write out a PEM copy of the cert, and a\n-\t\t\t\t * PEM copy of the private key, using the\n-\t\t\t\t * write-only fds we opened while we still\n-\t\t\t\t * had root.\n-\t\t\t\t *\n-\t\t\t\t * Estimate the size of the PEM version of the\n-\t\t\t\t * cert and allocate a temp buffer for it.\n-\t\t\t\t *\n-\t\t\t\t * This is a bit complicated because first we\n-\t\t\t\t * drop the b64url version into the buffer at\n-\t\t\t\t * +384, then we add the header at 0 and move\n-\t\t\t\t * lines of it back + '\u005cn' to make PEM.\n-\t\t\t\t *\n-\t\t\t\t * This avoids the need for two fullsize\n-\t\t\t\t * allocations.\n-\t\t\t\t */\n-\n-\t\t\t\tmax \u003d (ac-\u003ecpos * 4) / 3 + 16 + 384;\n-\n-\t\t\t\tstart \u003d p \u003d malloc(max);\n-\t\t\t\tif (!p)\n-\t\t\t\t\tgoto failed;\n-\n-\t\t\t\tn \u003d lws_b64_encode_string(ac-\u003ebuf, ac-\u003ecpos,\n-\t\t\t\t\t\t\t start + 384, max - 384);\n-\t\t\t\tif (n \u003c 0) {\n-\t\t\t\t\tfree(start);\n \t\t\t\t\tgoto failed;\n \t\t\t\t}\n+\t\t\t\tstrcpy(buf, ac-\u003efinalize_url);\n+\t\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext,\n+\t\t\t\t\t\tvhd-\u003evhost,\n+\t\t\t\t\t\t\u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n+\t\t\t\t\t\t\u0022POST\u0022);\n+\t\t\t\tif (!cwsi) {\n+\t\t\t\t\tlwsl_notice(\u0022%s: \u0022\n+\t\t\t\t\t\t\u0022failed to connect to acme\u005cn\u0022,\n+\t\t\t\t\t\t\t__func__);\n \n-\t\t\t\tpp \u003d start + 384;\n-\t\t\t\tp +\u003d lws_snprintf(start, 64, \u0022%s\u0022,\n-\t\t\t\t\t\t\u0022-----BEGIN CERTIFICATE-----\u005cn\u0022);\n-\n-\t\t\t\twhile (n) {\n-\t\t\t\t\tm \u003d 65;\n-\t\t\t\t\tif (n \u003c m)\n-\t\t\t\t\t\tm \u003d n;\n-\t\t\t\t\tmemcpy(p, pp, m);\n-\t\t\t\t\tn -\u003d m;\n-\t\t\t\t\tp +\u003d m;\n-\t\t\t\t\tpp +\u003d m;\n-\t\t\t\t\tif (n)\n-\t\t\t\t\t\t*p++ \u003d '\u005cn';\n-\t\t\t\t}\n-\t\t\t\tp +\u003d lws_snprintf(p,\n-\t\t\t\t\t\t max - lws_ptr_diff(p, start),\n-\t\t\t\t\t\t \u0022%s\u0022,\n-\t\t\t\t\t\t \u0022\u005cn-----END CERTIFICATE-----\u005cn\u0022);\n-\n-\t\t\t\tn \u003d lws_plat_write_cert(vhd-\u003evhost, 0,\n-\t\t\t\t\t\tvhd-\u003efd_updated_cert, start,\n-\t\t\t\t\t\tlws_ptr_diff(p, start));\n-\t\t\t\tfree(start);\n-\t\t\t\tif (n) {\n-\t\t\t\t\tlwsl_err(\u0022unable to write ACME cert! %d\u005cn\u0022, n);\n \t\t\t\t\tgoto failed;\n \t\t\t\t}\n-\t\t\t\t/*\n-\t\t\t\t * don't close it... we may update the certs\n-\t\t\t\t * again\n-\t\t\t\t */\n+\t\t\t\t/* close the completed client connection */\n+\t\t\t\treturn -1;\n+\t\t\t}\n \n-\t\t\t\tif (lws_plat_write_cert(vhd-\u003evhost, 1,\n-\t\t\t\t\t\t\tvhd-\u003efd_updated_key,\n-\t\t\t\t\t\t\tac-\u003ealloc_privkey_pem,\n-\t\t\t\t\t\t\tac-\u003elen_privkey_pem)) {\n-\t\t\t\t\tlwsl_err(\u0022unable to write ACME key!\u005cn\u0022);\n-\t\t\t\t\tgoto failed;\n-\t\t\t\t}\n+\t\t\tac-\u003estate \u003d ACME_STATE_DOWNLOAD_CERT;\n \n-\t\t\t\t/*\n-\t\t\t\t * we have written the persistent copies\n-\t\t\t\t */\n+\t\t\tstrcpy(buf, ac-\u003ecert_url);\n+\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n+\t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n+\t\t\t\t\t\t \u0022POST\u0022);\n+\t\t\tif (!cwsi) {\n+\t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n+\t\t\t\t\t\t__func__);\n \n-\t\t\t\tlwsl_notice(\u0022%s: Updated certs written for %s \u0022\n-\t\t\t\t\t \u0022to %s.upd and %s.upd\u005cn\u0022, __func__,\n-\t\t\t\t\t vhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],\n-\t\t\t\t\t vhd-\u003epvop_active[LWS_TLS_SET_CERT_PATH],\n-\t\t\t\t\t vhd-\u003epvop_active[LWS_TLS_SET_KEY_PATH]);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\t\t\treturn -1;\n \n-\t\t\t\t/* notify lws there was a cert update */\n+\t\tcase ACME_STATE_DOWNLOAD_CERT:\n \n-\t\t\t\tif (lws_tls_cert_updated(vhd-\u003econtext,\n-\t\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_CERT_PATH],\n-\t\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_KEY_PATH],\n-\t\t\t\t\tac-\u003ebuf, ac-\u003ecpos,\n-\t\t\t\t\tac-\u003ealloc_privkey_pem,\n-\t\t\t\t\tac-\u003elen_privkey_pem)) {\n-\t\t\t\t\tlwsl_notice(\u0022problem setting certs\u005cn\u0022);\n-\t\t\t\t}\n+\t\t\tif (ac-\u003eresp !\u003d 200) {\n+\t\t\t\tlwsl_notice(\u0022download cert failed on resp %d\u005cn\u0022,\n+\t\t\t\t\t ac-\u003eresp);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\t\t\tlwsl_notice(\u0022The cert was sent..\u005cn\u0022);\n \n-\t\t\t\tlws_acme_finished(vhd);\n-\t\t\t\tlws_acme_report_status(vhd-\u003evhost,\n-\t\t\t\t\t\t\tLWS_CUS_SUCCESS, NULL);\n+\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_ISSUE, NULL);\n \n-\t\t\t\treturn 0;\n+\t\t\t/*\n+\t\t\t * That means we have the issued cert in\n+\t\t\t * ac-\u003ebuf, length in ac-\u003ecpos; and the key in\n+\t\t\t * ac-\u003ealloc_privkey_pem, length in\n+\t\t\t * ac-\u003elen_privkey_pem.\n+\t\t\t */\n+\t\t\tn \u003d lws_plat_write_cert(vhd-\u003evhost, 0,\n+\t\t\t\t\tvhd-\u003efd_updated_cert,\n+\t\t\t\t\tac-\u003ebuf,\n+\t\t\t\t\tac-\u003ecpos);\n+\t\t\tif (n) {\n+\t\t\t\tlwsl_err(\u0022unable to write ACME cert! %d\u005cn\u0022, n);\n+\t\t\t\tgoto failed;\n \t\t\t}\n \n-\t\t\tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_CONFIRM, NULL);\n+\t\t\t/*\n+\t\t\t * don't close it... we may update the certs\n+\t\t\t * again\n+\t\t\t */\n+\t\t\tif (lws_plat_write_cert(vhd-\u003evhost, 1,\n+\t\t\t\t\t\tvhd-\u003efd_updated_key,\n+\t\t\t\t\t\tac-\u003ealloc_privkey_pem,\n+\t\t\t\t\t\tac-\u003elen_privkey_pem)) {\n+\t\t\t\tlwsl_err(\u0022unable to write ACME key!\u005cn\u0022);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n \n-\t\t\t/* he is preparing the cert, go again with a GET */\n+\t\t\t/*\n+\t\t\t * we have written the persistent copies\n+\t\t\t */\n+\t\t\tlwsl_notice(\u0022%s: Updated certs written for %s \u0022\n+\t\t\t\t\t\u0022to %s.upd and %s.upd\u005cn\u0022, __func__,\n+\t\t\tvhd-\u003epvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],\n+\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_CERT_PATH],\n+\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_KEY_PATH]);\n \n-\t\t\tif (ac-\u003egoes_around++ \u003d\u003d 30) {\n-\t\t\t\tlwsl_notice(\u0022%s: too many retries\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\t/* notify lws there was a cert update */\n \n-\t\t\t\tgoto failed;\n+\t\t\tif (lws_tls_cert_updated(vhd-\u003econtext,\n+\t\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_CERT_PATH],\n+\t\t\t\t\tvhd-\u003epvop_active[LWS_TLS_SET_KEY_PATH],\n+\t\t\t\t\t\tac-\u003ebuf, ac-\u003ecpos,\n+\t\t\t\t\t\tac-\u003ealloc_privkey_pem,\n+\t\t\t\t\t\tac-\u003elen_privkey_pem)) {\n+\t\t\t\tlwsl_notice(\u0022problem setting certs\u005cn\u0022);\n \t\t\t}\n \n-\t\t\tstrcpy(buf, ac-\u003echallenge_uri);\n-\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n-\t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei, buf,\n-\t\t\t\t\t\t \u0022GET\u0022);\n-\t\t\tif (!cwsi) {\n-\t\t\t\tlwsl_notice(\u0022%s: failed to connect to acme\u005cn\u0022,\n-\t\t\t\t\t __func__);\n+\t\t\tlws_acme_finished(vhd);\n+\t\t\tlws_acme_report_status(vhd-\u003evhost,\n+\t\t\t\t\tLWS_CUS_SUCCESS, NULL);\n \n-\t\t\t\tgoto failed;\n-\t\t\t}\n-\t\t\treturn -1; /* close the completed client connection */\n+\t\t\treturn -1;\n \n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n \t\tbreak;\n \n-\t\tcase LWS_CALLBACK_USER + 0xac33:\n-\t\t\tif (!vhd)\n-\t\t\t\tbreak;\n-\t\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n-\t\t\t\t\t\t \u0026ac-\u003ecwsi, \u0026ac-\u003ei,\n-\t\t\t\t\t\t ac-\u003echallenge_uri,\n-\t\t\t\t\t\t \u0022GET\u0022);\n-\t\t\tif (!cwsi) {\n-\t\t\t\tlwsl_notice(\u0022%s: failed to connect\u005cn\u0022, __func__);\n-\t\t\t\tgoto failed;\n-\t\t\t}\n+\tcase LWS_CALLBACK_USER + 0xac33:\n+\t\tif (!vhd)\n \t\t\tbreak;\n-\n-\tcase LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:\n-\t\t/*\n-\t\t * This goes to vhost-\u003eprotocols[0], but for our temp certs\n-\t\t * vhost we created, we have arranged that to be our protocol,\n-\t\t * so the callback will come here.\n-\t\t *\n-\t\t * When we created the temp vhost, we set its pvo to point\n-\t\t * to the ac associated with the temp vhost.\n-\t\t */\n-\t\tlwsl_debug(\u0022LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\u005cn\u0022);\n-\t\tac \u003d (struct acme_connection *)lws_get_vhost_user(\n-\t\t\t\t\t\t\t(struct lws_vhost *)in);\n-\n-\t\tlws_acme_report_status((struct lws_vhost *)in,\n-\t\t\t\t LWS_CUS_CREATE_REQ,\n-\t\t\t\t \u0022creating challenge cert\u0022);\n-\n-\t\tif (lws_tls_acme_sni_cert_create((struct lws_vhost *)in,\n-\t\t\t\t\t\t ac-\u003esan_a, ac-\u003esan_b)) {\n-\t\t\tlwsl_err(\u0022%s: creating the sni test cert failed\u005cn\u0022, __func__);\n-\n-\t\t\treturn -1;\n+\t\tcwsi \u003d lws_acme_client_connect(vhd-\u003econtext, vhd-\u003evhost,\n+\t\t\t\t\u0026ac-\u003ecwsi, \u0026ac-\u003ei,\n+\t\t\t\tac-\u003echallenge_uri,\n+\t\t\t\t\u0022GET\u0022);\n+\t\tif (!cwsi) {\n+\t\t\tlwsl_notice(\u0022%s: failed to connect\u005cn\u0022, __func__);\n+\t\t\tgoto failed;\n \t\t}\n \t\tbreak;\n \n@@ -1587,7 +1616,7 @@ poll_again:\n \treturn 0;\n \n failed:\n-\tlwsl_err(\u0022%s: failed out\u005cn\u0022, __func__);\n+\tlwsl_notice(\u0022%s: failed out\u005cn\u0022, __func__);\n \tlws_acme_report_status(vhd-\u003evhost, LWS_CUS_FAILED, failreason);\n \tlws_acme_finished(vhd);\n \n@@ -1606,7 +1635,7 @@ init_protocol_lws_acme_client(struct lws_context *context,\n {\n \tif (c-\u003eapi_magic !\u003d LWS_PLUGIN_API_MAGIC) {\n \t\tlwsl_err(\u0022Plugin API %d, library API %d\u0022, LWS_PLUGIN_API_MAGIC,\n-\t\t\t c-\u003eapi_magic);\n+\t\t\t\tc-\u003eapi_magic);\n \t\treturn 1;\n \t}\n \n","s":{"c":1745908453,"u": 12317}} ],"g": 16565,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}