static int callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get( lws_get_vhost(wsi), lws_get_protocol(wsi)); lws_sock_file_fd_type u; uint8_t buf[1024]; int n; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct raw_vhd)); vhd->filefd = lws_open(filepath, O_RDWR); if (vhd->filefd == -1) { lwsl_err("Unable to open %s\n", filepath); return 1; } u.filefd = (lws_filefd_type)(long long)vhd->filefd; if (!lws_adopt_descriptor_vhost(lws_get_vhost(wsi), LWS_ADOPT_RAW_FILE_DESC, u, "raw-test", NULL)) { lwsl_err("Failed to adopt fifo descriptor\n"); close(vhd->filefd); vhd->filefd = -1; return 1; } break; case LWS_CALLBACK_PROTOCOL_DESTROY: if (vhd && vhd->filefd != -1) close(vhd->filefd); break; /* callbacks related to raw file descriptor */ case LWS_CALLBACK_RAW_ADOPT_FILE: lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n"); break; case LWS_CALLBACK_RAW_RX_FILE: lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n"); n = read(vhd->filefd, buf, sizeof(buf)); if (n < 0) { lwsl_err("Reading from %s failed\n", filepath); return 1; } lwsl_hexdump_level(LLL_NOTICE, buf, n); break; case LWS_CALLBACK_RAW_CLOSE_FILE: lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n"); break; case LWS_CALLBACK_RAW_WRITEABLE_FILE: lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n"); /* * you can call lws_callback_on_writable() on a raw file wsi as * usual, and then write directly into the raw filefd here. */ break; default: break; } return 0; }
/* * notice this returns number of bytes consumed, or -1 */ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; size_t real_len = len; unsigned int n; // lwsl_hexdump_err(buf, len); /* * Detect if we got called twice without going through the * event loop to handle pending. This would be caused by either * back-to-back writes in one WRITABLE (illegal) or calling lws_write() * from outside the WRITABLE callback (illegal). */ if (wsi->could_have_pending) { lwsl_hexdump_level(LLL_ERR, buf, len); lwsl_err("** %p: vh: %s, prot: %s, role %s: " "Illegal back-to-back write of %lu detected...\n", wsi, wsi->vhost->name, wsi->protocol->name, wsi->role_ops->name, (unsigned long)len); // assert(0); return -1; } lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_WRITE, 1); if (!len) return 0; /* just ignore sends after we cleared the truncation buffer */ if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE && !wsi->trunc_len) return (int)len; if (wsi->trunc_len && (buf < wsi->trunc_alloc || buf > (wsi->trunc_alloc + wsi->trunc_len + wsi->trunc_offset))) { lwsl_hexdump_level(LLL_ERR, buf, len); lwsl_err("** %p: vh: %s, prot: %s, Sending new %lu, pending truncated ...\n" " It's illegal to do an lws_write outside of\n" " the writable callback: fix your code\n", wsi, wsi->vhost->name, wsi->protocol->name, (unsigned long)len); assert(0); return -1; } if (!wsi->http2_substream && !lws_socket_is_valid(wsi->desc.sockfd)) lwsl_warn("** error invalid sock but expected to send\n"); /* limit sending */ if (wsi->protocol->tx_packet_size) n = (int)wsi->protocol->tx_packet_size; else { n = (int)wsi->protocol->rx_buffer_size; if (!n) n = context->pt_serv_buf_size; } n += LWS_PRE + 4; if (n > len) n = (int)len; /* nope, send it on the socket directly */ lws_latency_pre(context, wsi); n = lws_ssl_capable_write(wsi, buf, n); lws_latency(context, wsi, "send lws_issue_raw", n, n == len); /* something got written, it can have been truncated now */ wsi->could_have_pending = 1; switch (n) { case LWS_SSL_CAPABLE_ERROR: /* we're going to close, let close know sends aren't possible */ wsi->socket_is_permanently_unusable = 1; return -1; case LWS_SSL_CAPABLE_MORE_SERVICE: /* * nothing got sent, not fatal. Retry the whole thing later, * ie, implying treat it was a truncated send so it gets * retried */ n = 0; break; } /* * we were already handling a truncated send? */ if (wsi->trunc_len) { lwsl_info("%p partial adv %d (vs %ld)\n", wsi, n, (long)real_len); wsi->trunc_offset += n; wsi->trunc_len -= n; if (!wsi->trunc_len) { lwsl_info("** %p partial send completed\n", wsi); /* done with it, but don't free it */ n = (int)real_len; if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { lwsl_info("** %p signalling to close now\n", wsi); return -1; /* retry closing now */ } } /* always callback on writeable */ lws_callback_on_writable(wsi); return n; } if ((unsigned int)n == real_len) /* what we just sent went out cleanly */ return n; /* * Newly truncated send. Buffer the remainder (it will get * first priority next time the socket is writable). */ lwsl_debug("%p new partial sent %d from %lu total\n", wsi, n, (unsigned long)real_len); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITE_PARTIALS, 1); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, n); /* * - if we still have a suitable malloc lying around, use it * - or, if too small, reallocate it * - or, if no buffer, create it */ if (!wsi->trunc_alloc || real_len - n > wsi->trunc_alloc_len) { lws_free(wsi->trunc_alloc); wsi->trunc_alloc_len = (unsigned int)(real_len - n); wsi->trunc_alloc = lws_malloc(real_len - n, "truncated send alloc"); if (!wsi->trunc_alloc) { lwsl_err("truncated send: unable to malloc %lu\n", (unsigned long)(real_len - n)); return -1; } } wsi->trunc_offset = 0; wsi->trunc_len = (unsigned int)(real_len - n); memcpy(wsi->trunc_alloc, buf + n, real_len - n); #if !defined(LWS_WITH_ESP32) if (lws_wsi_is_udp(wsi)) { /* stash original destination for fulfilling UDP partials */ wsi->udp->sa_pending = wsi->udp->sa; wsi->udp->salen_pending = wsi->udp->salen; } #endif /* since something buffered, force it to get another chance to send */ lws_callback_on_writable(wsi); return (int)real_len; }
LWS_VISIBLE int lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, const char *san_b) { int buflen = 0x560; uint8_t *buf = lws_malloc(buflen, "tmp cert buf"), *p = buf, *pkey_asn1; struct lws_genrsa_ctx ctx; struct lws_genrsa_elements el; uint8_t digest[32]; struct lws_genhash_ctx hash_ctx; int pkey_asn1_len = 3 * 1024; int n, keybits = lws_plat_recommended_rsa_bits(), adj; if (!buf) return 1; n = lws_genrsa_new_keypair(vhost->context, &ctx, &el, keybits); if (n < 0) { lws_jwk_destroy_genrsa_elements(&el); goto bail1; } n = sizeof(ss_cert_leadin); memcpy(p, ss_cert_leadin, n); p += n; adj = (0x0556 - 0x401) + (keybits / 4) + 1; buf[2] = adj >> 8; buf[3] = adj & 0xff; adj = (0x033e - 0x201) + (keybits / 8) + 1; buf[6] = adj >> 8; buf[7] = adj & 0xff; adj = (0x0222 - 0x201) + (keybits / 8) + 1; buf[0xc3] = adj >> 8; buf[0xc4] = adj & 0xff; adj = (0x020f - 0x201) + (keybits / 8) + 1; buf[0xd6] = adj >> 8; buf[0xd7] = adj & 0xff; adj = (0x020a - 0x201) + (keybits / 8) + 1; buf[0xdb] = adj >> 8; buf[0xdc] = adj & 0xff; *p++ = ((keybits / 8) + 1) >> 8; *p++ = ((keybits / 8) + 1) & 0xff; /* we need to drop 1 + (keybits / 8) bytes of n in here, 00 + key */ *p++ = 0x00; memcpy(p, el.e[JWK_KEY_N].buf, el.e[JWK_KEY_N].len); p += el.e[JWK_KEY_N].len; memcpy(p, ss_cert_san_leadin, sizeof(ss_cert_san_leadin)); p += sizeof(ss_cert_san_leadin); /* drop in 78 bytes of san_a */ memcpy(p, san_a, SAN_A_LENGTH); p += SAN_A_LENGTH; memcpy(p, ss_cert_sig_leadin, sizeof(ss_cert_sig_leadin)); p[17] = ((keybits / 8) + 1) >> 8; p[18] = ((keybits / 8) + 1) & 0xff; p += sizeof(ss_cert_sig_leadin); /* hash the cert plaintext */ if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256)) goto bail2; if (lws_genhash_update(&hash_ctx, buf, lws_ptr_diff(p, buf))) { lws_genhash_destroy(&hash_ctx, NULL); goto bail2; } if (lws_genhash_destroy(&hash_ctx, digest)) goto bail2; /* sign the hash */ n = lws_genrsa_public_sign(&ctx, digest, LWS_GENHASH_TYPE_SHA256, p, buflen - lws_ptr_diff(p, buf)); if (n < 0) goto bail2; p += n; pkey_asn1 = lws_malloc(pkey_asn1_len, "mbed crt tmp"); if (!pkey_asn1) goto bail2; n = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, pkey_asn1_len); if (n < 0) { lws_free(pkey_asn1); goto bail2; } lwsl_debug("private key\n"); lwsl_hexdump_level(LLL_DEBUG, pkey_asn1, n); /* and to use our generated private key */ n = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, pkey_asn1, n); lws_free(pkey_asn1); if (n != 1) { lwsl_notice("%s: SSL_CTX_use_PrivateKey_ASN1 failed\n", __func__); } lws_genrsa_destroy(&ctx); lws_jwk_destroy_genrsa_elements(&el); if (n == 1) { lwsl_hexdump_level(LLL_DEBUG, buf, lws_ptr_diff(p, buf)); n = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, lws_ptr_diff(p, buf), buf); if (n != 1) lwsl_notice("%s: generated cert failed to load 0x%x\n", __func__, -n); } lws_free(buf); return n != 1; bail2: lws_genrsa_destroy(&ctx); lws_jwk_destroy_genrsa_elements(&el); bail1: lws_free(buf); return -1; }