|
@@ -1,12 +1,21 @@
|
|
-#include <stdio.h>
|
|
|
|
|
|
+/* Example for embedding a server including the HTTPS server key and
|
|
|
|
+ * certificate. All response is generated from a callback. The server
|
|
|
|
+ * does not access the file system at all. */
|
|
|
|
+/* Building: change into the examples/embed_certificate folder and
|
|
|
|
+ * use "./build.sh" on Linux (no, you don't need a Makefile). */
|
|
|
|
+
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/ssl.h>
|
|
#include <stdint.h>
|
|
#include <stdint.h>
|
|
|
|
+#include <stdio.h>
|
|
#include <string.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
|
|
|
#include "civetweb.h"
|
|
#include "civetweb.h"
|
|
|
|
|
|
-/* server.crt BASE64 to HEX */
|
|
|
|
|
|
+/* This array corresponds to the content of the file
|
|
|
|
+ * /resources/cert/server.crt converted from BASE64 to HEX.
|
|
|
|
+ * When using this code, you need to REPLACE IT BY YOUR OWN CERTIFICATE!
|
|
|
|
+ */
|
|
const uint8_t SSL_CERT_ASN1[] = {
|
|
const uint8_t SSL_CERT_ASN1[] = {
|
|
0x30, 0x82, 0x04, 0x40, 0x30, 0x82, 0x03, 0x28, 0xa0, 0x03, 0x02, 0x01,
|
|
0x30, 0x82, 0x04, 0x40, 0x30, 0x82, 0x03, 0x28, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x49, 0x65, 0x5b, 0x35, 0xce, 0x42, 0x20, 0x15, 0xa7,
|
|
0x02, 0x02, 0x14, 0x49, 0x65, 0x5b, 0x35, 0xce, 0x42, 0x20, 0x15, 0xa7,
|
|
@@ -100,7 +109,11 @@ const uint8_t SSL_CERT_ASN1[] = {
|
|
0xf7, 0xee, 0x48, 0x41, 0x93, 0x69, 0x7c, 0x3e, 0x47, 0xf0, 0x5e, 0x60,
|
|
0xf7, 0xee, 0x48, 0x41, 0x93, 0x69, 0x7c, 0x3e, 0x47, 0xf0, 0x5e, 0x60,
|
|
0x5d, 0x1d, 0xa3, 0x67, 0x59, 0x3c, 0xf9, 0x3c, 0x49, 0x63, 0x74, 0x84};
|
|
0x5d, 0x1d, 0xa3, 0x67, 0x59, 0x3c, 0xf9, 0x3c, 0x49, 0x63, 0x74, 0x84};
|
|
|
|
|
|
-/* server.key BASE64 to HEX */
|
|
|
|
|
|
+
|
|
|
|
+/* This array corresponds to the content of the file
|
|
|
|
+ * /resources/cert/server.key converted from BASE64 to HEX.
|
|
|
|
+ * When using this code, you need to REPLACE IT BY YOUR OWN PRIVATE KEY!
|
|
|
|
+ */
|
|
const uint8_t SSL_KEY_ASN1[] = {
|
|
const uint8_t SSL_KEY_ASN1[] = {
|
|
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
|
|
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
|
|
0xca, 0x25, 0x51, 0xe7, 0xb4, 0x06, 0x2d, 0x11, 0xe1, 0x33, 0xfb, 0xde,
|
|
0xca, 0x25, 0x51, 0xe7, 0xb4, 0x06, 0x2d, 0x11, 0xe1, 0x33, 0xfb, 0xde,
|
|
@@ -204,6 +217,17 @@ const uint8_t SSL_KEY_ASN1[] = {
|
|
0xcc, 0x75};
|
|
0xcc, 0x75};
|
|
|
|
|
|
|
|
|
|
|
|
+/* This is an example for a custom SSL initialization function.
|
|
|
|
+ * It will setup the certificate and private key defined in the arrays above.
|
|
|
|
+ * Thus, they do not need to be located in files in the file system.
|
|
|
|
+ * To slightly improve security, you could use some encryption for the arrays
|
|
|
|
+ * above, and only decrypt it in memory before passing to the SSL_CTX_use_*
|
|
|
|
+ * functions. Then the data will not exist in the executable stored at the
|
|
|
|
+ * disk, but only in memory at runtime - making reverse engineering more
|
|
|
|
+ * complex. Here we use unencrypted versions, so you could test the conversion
|
|
|
|
+ * process from server.key/server.crt to these arrays on your own, and see if
|
|
|
|
+ * you come to the same result.
|
|
|
|
+ */
|
|
static int
|
|
static int
|
|
init_ssl(void *ssl_ctx, void *user_data)
|
|
init_ssl(void *ssl_ctx, void *user_data)
|
|
{
|
|
{
|
|
@@ -224,12 +248,18 @@ init_ssl(void *ssl_ctx, void *user_data)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+/* This handler function will serve all requests to the server.
|
|
|
|
+ * In a realistic example, you would have multiple handler functions for
|
|
|
|
+ * different URLs.
|
|
|
|
+ */
|
|
static int
|
|
static int
|
|
request_handler(struct mg_connection *conn, void *cbdata)
|
|
request_handler(struct mg_connection *conn, void *cbdata)
|
|
{
|
|
{
|
|
|
|
+ /* Get the URI from the request info. */
|
|
const struct mg_request_info *ri = mg_get_request_info(conn);
|
|
const struct mg_request_info *ri = mg_get_request_info(conn);
|
|
unsigned uri_len = (unsigned)strlen(ri->local_uri);
|
|
unsigned uri_len = (unsigned)strlen(ri->local_uri);
|
|
|
|
|
|
|
|
+ /* Example: get a cookie named "c" from the client. */
|
|
const char *cookie = mg_get_header(conn, "Cookie");
|
|
const char *cookie = mg_get_header(conn, "Cookie");
|
|
unsigned long cookie_number = 0;
|
|
unsigned long cookie_number = 0;
|
|
if (cookie) {
|
|
if (cookie) {
|
|
@@ -241,22 +271,29 @@ request_handler(struct mg_connection *conn, void *cbdata)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ /* Calculate a value for a new cookie. Here just increment the previous
|
|
|
|
+ * value. Thus, we count the number of times a client visited this a
|
|
|
|
+ * page generated by this handler function. */
|
|
char new_cookie[32];
|
|
char new_cookie[32];
|
|
sprintf(new_cookie, "c=%u", cookie_number + 1);
|
|
sprintf(new_cookie, "c=%u", cookie_number + 1);
|
|
|
|
|
|
- int status = 200;
|
|
|
|
|
|
+ /* Generate a response text and status code. */
|
|
|
|
+ int status;
|
|
char response[1024];
|
|
char response[1024];
|
|
|
|
|
|
if (uri_len <= 100) {
|
|
if (uri_len <= 100) {
|
|
|
|
+ status = 200; /* 200 = OK */
|
|
sprintf(response,
|
|
sprintf(response,
|
|
"Hello at %s\nYou have visited %u sites here before!",
|
|
"Hello at %s\nYou have visited %u sites here before!",
|
|
ri->local_uri,
|
|
ri->local_uri,
|
|
cookie_number);
|
|
cookie_number);
|
|
} else {
|
|
} else {
|
|
- status = 404;
|
|
|
|
|
|
+ /* We don't like this URL */
|
|
|
|
+ status = 404; /* 404 = Not Found */
|
|
sprintf(response, "No such URL\n");
|
|
sprintf(response, "No such URL\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* This sequence can be used to send a response including a cookie. */
|
|
unsigned content_len = (unsigned)strlen(response);
|
|
unsigned content_len = (unsigned)strlen(response);
|
|
char content_len_text[32];
|
|
char content_len_text[32];
|
|
sprintf(content_len_text, "%u", content_len);
|
|
sprintf(content_len_text, "%u", content_len);
|
|
@@ -275,6 +312,7 @@ request_handler(struct mg_connection *conn, void *cbdata)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+/* Main: Initialize and run the server */
|
|
int
|
|
int
|
|
main(int argc, char *argv[])
|
|
main(int argc, char *argv[])
|
|
{
|
|
{
|
|
@@ -289,14 +327,20 @@ main(int argc, char *argv[])
|
|
|
|
|
|
init.user_data = NULL;
|
|
init.user_data = NULL;
|
|
|
|
|
|
- const char *options[] = {"listening_ports", "80r,443s",
|
|
|
|
- "authentication_domain", "localhost",
|
|
|
|
- "enable_auth_domain_check", "no",
|
|
|
|
- "ssl_protocol_version", "4",
|
|
|
|
- "ssl_cipher_list", "ECDH+AESGCM+AES256:!aNULL:!MD5:!DSS",
|
|
|
|
- "strict_transport_security_max_age", "15552000",
|
|
|
|
- NULL, NULL}
|
|
|
|
- ;
|
|
|
|
|
|
+ const char *options[] = {"listening_ports",
|
|
|
|
+ "80r,443s",
|
|
|
|
+ "authentication_domain",
|
|
|
|
+ "localhost",
|
|
|
|
+ "enable_auth_domain_check",
|
|
|
|
+ "no",
|
|
|
|
+ "ssl_protocol_version",
|
|
|
|
+ "4",
|
|
|
|
+ "ssl_cipher_list",
|
|
|
|
+ "ECDH+AESGCM+AES256:!aNULL:!MD5:!DSS",
|
|
|
|
+ "strict_transport_security_max_age",
|
|
|
|
+ "15552000",
|
|
|
|
+ NULL,
|
|
|
|
+ NULL};
|
|
init.configuration_options = options;
|
|
init.configuration_options = options;
|
|
|
|
|
|
struct mg_error_data error = {0};
|
|
struct mg_error_data error = {0};
|