Ver código fonte

Merge pull request #217 from MGralka/ssl_client

Use SSL client certificates
bel2125 9 anos atrás
pai
commit
b9b940577a
4 arquivos alterados com 92 adições e 5 exclusões
  1. 5 1
      .gitignore
  2. 24 1
      docs/UserManual.md
  3. 60 2
      src/civetweb.c
  4. 3 1
      src/main.c

+ 5 - 1
.gitignore

@@ -67,6 +67,7 @@ local.properties
 # Build results
 # Build results
 
 
 [Dd]ebug/
 [Dd]ebug/
+[Dd]ebug CONSOLE/
 [Rr]elease/
 [Rr]elease/
 x64/
 x64/
 [Bb]in/
 [Bb]in/
@@ -244,7 +245,8 @@ requests.db
 ##########################
 ##########################
 ## Files created by ctags
 ## Files created by ctags
 ##########################
 ##########################
-tags
+?tags
+?tags?
 
 
 ##########################
 ##########################
 ## Files created by autotools
 ## Files created by autotools
@@ -256,3 +258,5 @@ tags
 ## Travis Build Dir
 ## Travis Build Dir
 ##########################
 ##########################
 ci/lua
 ci/lua
+
+

+ 24 - 1
docs/UserManual.md

@@ -386,6 +386,30 @@ See the [Wikipedia page on HTTP status codes](http://en.wikipedia.org/wiki/HTTP_
 URL encoded request strings are decoded in the server, unless it is disabled
 URL encoded request strings are decoded in the server, unless it is disabled
 by setting this option to `no`.
 by setting this option to `no`.
 
 
+### ssl_verify_peer `no`
+Enable client's certificate verification by the server.
+
+### ssl_ca_path
+Name of a directory containing trusted CA certificates. Each file in the
+directory must contain only a single CA certificate. The files must be named
+by the subject name’s hash and an extension of “.0”. If there is more than one
+certificate with the same subject name they should have extensions ".0", ".1",
+".2" and so on respectively.
+
+### ssl_ca_file
+Path to a .pem file containing trusted certificates. The file may contain
+more than one certificate.
+
+### ssl_verify_depth `9`
+Sets maximum depth of certificate chain. If client's certificate chain is longer
+than the depth set here connection is refused.
+
+### ssl_default_verify_paths `yes`
+Loads default trusted certificates locations set at openssl compile time.
+
+### ssl_forward_secrecy `yes`
+Enable [forward secrecy](https://en.wikipedia.org/wiki/Forward_secrecy).
+
 # Lua Scripts and Lua Server Pages
 # Lua Scripts and Lua Server Pages
 Pre-built Windows and Mac civetweb binaries have built-in Lua scripting
 Pre-built Windows and Mac civetweb binaries have built-in Lua scripting
 support as well as support for Lua Server Pages.
 support as well as support for Lua Server Pages.
@@ -549,4 +573,3 @@ An example is shown in
 - Embedding with OpenSSL on Windows might fail because of calling convention.
 - Embedding with OpenSSL on Windows might fail because of calling convention.
   To force Civetweb to use `__stdcall` convention, add `/Gz` compilation
   To force Civetweb to use `__stdcall` convention, add `/Gz` compilation
   flag in Visual Studio compiler.
   flag in Visual Studio compiler.
-

+ 60 - 2
src/civetweb.c

@@ -811,6 +811,7 @@ typedef int socklen_t;
 typedef struct ssl_st SSL;
 typedef struct ssl_st SSL;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_ctx_st SSL_CTX;
 typedef struct ssl_ctx_st SSL_CTX;
+typedef struct x5099_store_ctx_st X509_STORE_CTX;
 
 
 struct ssl_func {
 struct ssl_func {
 	const char *name;  /* SSL function name */
 	const char *name;  /* SSL function name */
@@ -842,6 +843,11 @@ struct ssl_func {
 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
 #define SSL_CTX_set_verify (*(void (*)(SSL_CTX *, int, int))ssl_sw[19].ptr)
 #define SSL_CTX_set_verify (*(void (*)(SSL_CTX *, int, int))ssl_sw[19].ptr)
 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
+#define SSL_CTX_load_verify_locations 										   \
+(*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
+#define SSL_CTX_set_default_verify_paths									   \
+(*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
+#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
 
 
 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
 #define CRYPTO_set_locking_callback                                            \
 #define CRYPTO_set_locking_callback                                            \
@@ -876,6 +882,9 @@ static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
                                    {"SSL_pending", NULL},
                                    {"SSL_pending", NULL},
                                    {"SSL_CTX_set_verify", NULL},
                                    {"SSL_CTX_set_verify", NULL},
                                    {"SSL_shutdown", NULL},
                                    {"SSL_shutdown", NULL},
+                                   {"SSL_CTX_load_verify_locations", NULL},
+                                   {"SSL_CTX_set_default_verify_paths", NULL},
+                                   {"SSL_CTX_set_verify_depth", NULL},
                                    {NULL, NULL}};
                                    {NULL, NULL}};
 
 
 /* Similar array as ssl_sw. These functions could be located in different
 /* Similar array as ssl_sw. These functions could be located in different
@@ -971,6 +980,12 @@ enum {
 	REWRITE,
 	REWRITE,
 	HIDE_FILES,
 	HIDE_FILES,
 	REQUEST_TIMEOUT,
 	REQUEST_TIMEOUT,
+	SSL_VERIFY_PEER,
+	SSL_CA_PATH,
+	SSL_CA_FILE,
+	SSL_VERIFY_DEPTH,
+	SSL_DEFAULT_VERIFY_PATHS,
+	SSL_FORWARD_SECRECY,
 #if defined(USE_WEBSOCKET)
 #if defined(USE_WEBSOCKET)
 	WEBSOCKET_TIMEOUT,
 	WEBSOCKET_TIMEOUT,
 #endif
 #endif
@@ -1030,6 +1045,12 @@ static struct mg_option config_options[] = {
     {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL},
     {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL},
     {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL},
     {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL},
     {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
     {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
+	{"ssl_verify_peer", CONFIG_TYPE_BOOLEAN, "no"},
+	{"ssl_ca_path", CONFIG_TYPE_DIRECTORY, NULL},
+	{"ssl_ca_file", CONFIG_TYPE_FILE, NULL},
+	{"ssl_verify_depth", CONFIG_TYPE_NUMBER, "9"},
+	{"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN, "yes"},
+	{"ssl_forward_secrecy", CONFIG_TYPE_BOOLEAN, "yes"},
 #if defined(USE_WEBSOCKET)
 #if defined(USE_WEBSOCKET)
     {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
     {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
 #endif
 #endif
@@ -9872,7 +9893,8 @@ sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *))
 		return 0;
 		return 0;
 	}
 	}
 
 
-	return (conn->ssl = SSL_new(s)) != NULL
+	conn->ssl = SSL_new(s);
+	return (conn->ssl != NULL)
 	       && SSL_set_fd(conn->ssl, conn->client.sock) == 1
 	       && SSL_set_fd(conn->ssl, conn->client.sock) == 1
 	       && func(conn->ssl) == 1;
 	       && func(conn->ssl) == 1;
 }
 }
@@ -10004,6 +10026,11 @@ set_ssl_option(struct mg_context *ctx)
 {
 {
 	const char *pem;
 	const char *pem;
 	int callback_ret;
 	int callback_ret;
+	int should_verify_peer;
+	const char* ca_path;
+	const char* ca_file;
+	int use_default_verify_paths;
+	int verify_depth;
 
 
 	/* If PEM file is not specified and the init_ssl callback
 	/* If PEM file is not specified and the init_ssl callback
 	 * is not specified, skip SSL initialization. */
 	 * is not specified, skip SSL initialization. */
@@ -10068,6 +10095,36 @@ set_ssl_option(struct mg_context *ctx)
 		(void)SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
 		(void)SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
 	}
 	}
 
 
+	should_verify_peer = (ctx->config[SSL_VERIFY_PEER] != NULL)
+		&& (mg_strcasecmp(ctx->config[SSL_VERIFY_PEER], "yes") == 0);
+
+	use_default_verify_paths = (ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
+			&& (mg_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
+
+	if (should_verify_peer) {
+		ca_path = ctx->config[SSL_CA_PATH];
+		ca_file = ctx->config[SSL_CA_FILE];
+		if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, ca_path) != 1) {
+			mg_cry(fc(ctx), "SSL_CTX_load_verify_locations error: %s "
+		    "ssl_verify_peer requires setting "
+			"either ssl_ca_path or ssl_ca_file. Is any of them present in "
+			"the .conf file?", ssl_error());
+			return 0;
+		}
+		SSL_CTX_set_verify(ctx->ssl_ctx, 3, 0);
+
+		if (use_default_verify_paths
+		&& SSL_CTX_set_default_verify_paths(ctx->ssl_ctx) != 1) {
+			mg_cry(fc(ctx), "SSL_CTX_set_default_verify_paths error: %s", ssl_error());
+			return 0;
+		}
+
+		if (ctx->config[SSL_VERIFY_DEPTH]){
+			verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
+			SSL_CTX_set_verify_depth(ctx->ssl_ctx, verify_depth);
+		}
+	}
+
 	return 1;
 	return 1;
 }
 }
 
 
@@ -10368,7 +10425,8 @@ mg_connect_client(const char *host,
 		(void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
 		(void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
 #ifndef NO_SSL
 #ifndef NO_SSL
 		if (use_ssl) {
 		if (use_ssl) {
-			/* SSL_CTX_set_verify call is needed to switch off server
+			/* TODO: Check ssl_verify_peer and ssl_ca_path here.
+			   SSL_CTX_set_verify call is needed to switch off server
 			 * certificate checking, which is off by default in OpenSSL and on
 			 * certificate checking, which is off by default in OpenSSL and on
 			 * in yaSSL. */
 			 * in yaSSL. */
 			SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
 			SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);

+ 3 - 1
src/main.c

@@ -1015,6 +1015,8 @@ start_civetweb(int argc, char *argv[])
 	verify_existence(options, "document_root", 1);
 	verify_existence(options, "document_root", 1);
 	verify_existence(options, "cgi_interpreter", 0);
 	verify_existence(options, "cgi_interpreter", 0);
 	verify_existence(options, "ssl_certificate", 0);
 	verify_existence(options, "ssl_certificate", 0);
+	verify_existence(options, "ssl_ca_path", 1);
+	verify_existence(options, "ssl_ca_file", 0);
 #ifdef USE_LUA
 #ifdef USE_LUA
 	verify_existence(options, "lua_preload_file", 0);
 	verify_existence(options, "lua_preload_file", 0);
 #endif
 #endif
@@ -1689,7 +1691,7 @@ show_settings_dialog()
 #define WIDTH (460)
 #define WIDTH (460)
 #define LABEL_WIDTH (90)
 #define LABEL_WIDTH (90)
 
 
-	unsigned char mem[4096], *p;
+	unsigned char mem[8192], *p;
 	const struct mg_option *options;
 	const struct mg_option *options;
 	DWORD style;
 	DWORD style;
 	DLGTEMPLATE *dia = (DLGTEMPLATE *)mem;
 	DLGTEMPLATE *dia = (DLGTEMPLATE *)mem;