| 1749 | } |
| 1750 | |
| 1751 | static void handle_ui_readiness(cbm_http_server_t *srv, cbm_http_conn_t *c, |
| 1752 | const cbm_http_req_t *req) { |
| 1753 | if (!srv->readiness_secret_set) { |
| 1754 | cbm_http_replyf(c, 503, "Cache-Control: no-store\r\n", "%s", "readiness proof unavailable"); |
| 1755 | return; |
| 1756 | } |
| 1757 | char challenge_hex[CBM_SHA256_HEX_LEN + 1U]; |
| 1758 | uint8_t challenge[CBM_SHA256_DIGEST_LEN]; |
| 1759 | static const char prefix[] = "challenge="; |
| 1760 | if (strncmp(req->query, prefix, sizeof(prefix) - 1U) != 0 || |
| 1761 | strlen(req->query) != sizeof(prefix) - 1U + CBM_SHA256_HEX_LEN) { |
| 1762 | cbm_http_replyf(c, 400, "Cache-Control: no-store\r\n", "%s", "invalid challenge"); |
| 1763 | return; |
| 1764 | } |
| 1765 | memcpy(challenge_hex, req->query + sizeof(prefix) - 1U, CBM_SHA256_HEX_LEN); |
| 1766 | challenge_hex[CBM_SHA256_HEX_LEN] = '\0'; |
| 1767 | if (!readiness_hex_decode(challenge_hex, challenge)) { |
| 1768 | cbm_secure_zero(challenge, sizeof(challenge)); |
| 1769 | cbm_http_replyf(c, 400, "Cache-Control: no-store\r\n", "%s", "invalid challenge"); |
| 1770 | return; |
| 1771 | } |
| 1772 | uint8_t proof[CBM_SHA256_DIGEST_LEN]; |
| 1773 | char proof_hex[CBM_SHA256_HEX_LEN + 1U]; |
| 1774 | cbm_hmac_sha256(srv->readiness_secret, sizeof(srv->readiness_secret), challenge, |
| 1775 | sizeof(challenge), proof); |
| 1776 | readiness_hex_encode(proof, proof_hex); |
| 1777 | cbm_http_replyf(c, 200, |
| 1778 | "Content-Type: text/plain; charset=utf-8\r\n" |
| 1779 | "Cache-Control: no-store\r\n" |
| 1780 | "X-Content-Type-Options: nosniff\r\n", |
| 1781 | "%s", proof_hex); |
| 1782 | cbm_secure_zero(challenge, sizeof(challenge)); |
| 1783 | cbm_secure_zero(proof, sizeof(proof)); |
| 1784 | cbm_secure_zero(proof_hex, sizeof(proof_hex)); |
| 1785 | } |
| 1786 | |
| 1787 | static bool request_passes_http_security(cbm_http_server_t *srv, cbm_http_conn_t *c, |
| 1788 | const cbm_http_req_t *req) { |
no test coverage detected