From 4a0cc8223e9805524e3a1d583ef848bf9efd178d Mon Sep 17 00:00:00 2001
From: Deomid Ryabkov <rojer@cesanta.com>
Date: Wed, 24 Feb 2016 14:14:07 +0100
Subject: [PATCH] Add SSL options to mg_{bind,connect}_opt

    PUBLISHED_FROM=7e28eb43742b76c073c9c2c879c64d7b4d3e9a7e
---
 mongoose.c | 38 ++++++++++++++++++++++++++++++++++++++
 mongoose.h | 34 +++++++++++++++++++++++++++-------
 2 files changed, 65 insertions(+), 7 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index 35ce2cfa5..6a20d0eb9 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2525,6 +2525,10 @@ const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
   const char *result = NULL;
   DBG(("%p %s %s", nc, (cert ? cert : ""), (ca_cert ? ca_cert : "")));
 
+  if (nc->flags & MG_F_UDP) {
+    return "SSL for UDP is not supported";
+  }
+
   if (nc->ssl != NULL) {
     SSL_free(nc->ssl);
     nc->ssl = NULL;
@@ -2786,6 +2790,30 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
   nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
   nc->user_data = opts.user_data;
 
+#ifdef MG_ENABLE_SSL
+  if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
+    const char *err = mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
+    if (err != NULL) {
+      MG_SET_PTRPTR(opts.error_string, err);
+      mg_destroy_conn(nc);
+      return NULL;
+    }
+    if (opts.ssl_ca_cert != NULL && (opts.ssl_server_name == NULL ||
+                                     strcmp(opts.ssl_server_name, "*") != 0)) {
+      if (opts.ssl_server_name == NULL) opts.ssl_server_name = host;
+#ifdef SSL_KRYPTON
+      SSL_CTX_kr_set_verify_name(nc->ssl_ctx, opts.ssl_server_name);
+#else
+      /* TODO(rojer): Implement server name verification on OpenSSL. */
+      MG_SET_PTRPTR(opts.error_string,
+                    "Server name verification requested but is not supported");
+      mg_destroy_conn(nc);
+      return NULL;
+#endif /* SSL_KRYPTON */
+    }
+  }
+#endif /* MG_ENABLE_SSL */
+
   if (rc == 0) {
 #ifndef MG_DISABLE_RESOLVER
     /*
@@ -2858,6 +2886,16 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
     mg_destroy_conn(nc);
     return NULL;
   }
+#ifdef MG_ENABLE_SSL
+  if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
+    const char *err = mg_set_ssl(nc, opts.ssl_cert, opts.ssl_ca_cert);
+    if (err != NULL) {
+      MG_SET_PTRPTR(opts.error_string, err);
+      mg_destroy_conn(nc);
+      return NULL;
+    }
+  }
+#endif /* MG_ENABLE_SSL */
   mg_add_conn(nc->mgr, nc);
 
   return nc;
diff --git a/mongoose.h b/mongoose.h
index 928b49e5c..4b198f90b 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -1191,6 +1191,11 @@ struct mg_bind_opts {
   void *user_data;           /* Initial value for connection's user_data */
   unsigned int flags;        /* Extra connection flags */
   const char **error_string; /* Placeholder for the error string */
+#ifdef MG_ENABLE_SSL
+  /* SSL settings. */
+  const char *ssl_cert;    /* Server certificate to present to clients */
+  const char *ssl_ca_cert; /* Verify client certificates with this CA bundle */
+#endif
 };
 
 /*
@@ -1217,14 +1222,29 @@ struct mg_connection *mg_bind(struct mg_mgr *, const char *,
  * Return a new listening connection, or `NULL` on error.
  * NOTE: Connection remains owned by the manager, do not free().
  */
-struct mg_connection *mg_bind_opt(struct mg_mgr *, const char *,
-                                  mg_event_handler_t, struct mg_bind_opts);
+struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
+                                  mg_event_handler_t handler,
+                                  struct mg_bind_opts opts);
 
 /* Optional parameters to mg_connect_opt() */
 struct mg_connect_opts {
   void *user_data;           /* Initial value for connection's user_data */
   unsigned int flags;        /* Extra connection flags */
   const char **error_string; /* Placeholder for the error string */
+#ifdef MG_ENABLE_SSL
+  /* SSL settings. */
+  const char *ssl_cert;    /* Client certificate to present to the server */
+  const char *ssl_ca_cert; /* Verify server certificate using this CA bundle */
+
+  /*
+   * Server name verification. If ssl_ca_cert is set and the certificate has
+   * passed verification, its subject will be verified against this string.
+   * By default (if ssl_server_name is NULL) hostname part of the address will
+   * be used. Wildcard matching is supported. A special value of "*" disables
+   * name verification.
+   */
+  const char *ssl_server_name;
+#endif
 };
 
 /*
@@ -1232,8 +1252,8 @@ struct mg_connect_opts {
  *
  * See `mg_connect_opt()` for full documentation.
  */
-struct mg_connection *mg_connect(struct mg_mgr *, const char *,
-                                 mg_event_handler_t);
+struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
+                                 mg_event_handler_t handler);
 
 /*
  * Connect to a remote host.
@@ -1284,9 +1304,9 @@ struct mg_connection *mg_connect(struct mg_mgr *, const char *,
  *   mg_connect(mgr, "my_site.com:80", ev_handler);
  * ----
  */
-struct mg_connection *mg_connect_opt(struct mg_mgr *, const char *,
-                                     mg_event_handler_t,
-                                     struct mg_connect_opts);
+struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
+                                     mg_event_handler_t handler,
+                                     struct mg_connect_opts opts);
 
 /*
  * Enable SSL for a given connection.
-- 
GitLab