Welcome! Log In Create A New Profile

Advanced

[PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Sven Peter
January 13, 2014 05:30AM
# HG changeset patch
# User Sven Peter <sven@ha.cki.ng>
# Date 1389607375 -3600
# Mon Jan 13 11:02:55 2014 +0100
# Node ID 8744640301ae0f7d4c16108e68c9ae6eb60f2213
# Parent 4aa64f6950313311e0d322a2af1788edeb7f036c
mail_{ssl,auth_http}_module: add support for SSL client certificates

This patch adds support for SSL client certificates to the mail proxy
capabilities of nginx both for STARTTLS and SSL mode.
Just like the HTTP SSL module a root CA is defined in the mail section
of the configuration file. Verification can be optional or mandatory.
Additionally, the result of the verification is exposed to the
auth http backend via the SSL-Verify, SSL-Subject-DN and SSL-Issuer-DN
HTTP headers.

diff -r 4aa64f695031 -r 8744640301ae src/mail/ngx_mail_auth_http_module.c
--- a/src/mail/ngx_mail_auth_http_module.c Sat Jan 04 03:32:22 2014 +0400
+++ b/src/mail/ngx_mail_auth_http_module.c Mon Jan 13 11:02:55 2014 +0100
@@ -1144,6 +1144,11 @@
ngx_buf_t *b;
ngx_str_t login, passwd;
ngx_mail_core_srv_conf_t *cscf;
+ ngx_str_t ssl_client_verify = {0, NULL};
+ ngx_str_t ssl_client_raw_s_dn = {0, NULL};
+ ngx_str_t ssl_client_raw_i_dn = {0, NULL};
+ ngx_str_t ssl_client_s_dn = {0, NULL};
+ ngx_str_t ssl_client_i_dn = {0, NULL};

if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
return NULL;
@@ -1153,6 +1158,29 @@
return NULL;
}

+ // ssl_client_verify doesn't need to be escaped since it comes from nginx itself
+#if (NGX_MAIL_SSL)
+ ngx_ssl_get_client_verify(s->connection, pool, &ssl_client_verify);
+ ngx_ssl_get_subject_dn(s->connection, pool, &ssl_client_s_dn);
+ ngx_ssl_get_subject_dn(s->connection, pool, &ssl_client_i_dn);
+
+ if (ssl_client_raw_s_dn.len != 0) {
+ if (ngx_mail_auth_http_escape(pool, &ssl_client_raw_s_dn, &ssl_client_s_dn) != NGX_OK) {
+ return NULL;
+ }
+ }
+
+ if (ssl_client_raw_i_dn.len != 0) {
+ if (ngx_mail_auth_http_escape(pool, &ssl_client_raw_i_dn, &ssl_client_i_dn) != NGX_OK) {
+ return NULL;
+ }
+ }
+#else
+ // avoid -Wunused-variable
+ (void)ssl_client_raw_i_dn;
+ (void)ssl_client_raw_s_dn;
+#endif
+
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
@@ -1173,6 +1201,9 @@
+ sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
+ sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
+ sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
+ + sizeof("SSL-Verify: ") - 1 + ssl_client_verify.len + sizeof(CRLF) - 1
+ + sizeof("SSL-Subject-DN: ") - 1 + ssl_client_s_dn.len + sizeof(CRLF) - 1
+ + sizeof("SSL-Issuer-DN: ") - 1 + ssl_client_i_dn.len + sizeof(CRLF) - 1
+ ahcf->header.len
+ sizeof(CRLF) - 1;

@@ -1255,6 +1286,20 @@

}

+ if (ssl_client_verify.len && ssl_client_s_dn.len && ssl_client_i_dn.len) {
+ b->last = ngx_cpymem(b->last, "SSL-Verify: ", sizeof("SSL-Verify: ") - 1);
+ b->last = ngx_copy(b->last, ssl_client_verify.data, ssl_client_verify.len);
+ *b->last++ = CR; *b->last++ = LF;
+
+ b->last = ngx_cpymem(b->last, "SSL-Subject-DN: ", sizeof("SSL-Subject-DN: ") - 1);
+ b->last = ngx_copy(b->last, ssl_client_s_dn.data, ssl_client_s_dn.len);
+ *b->last++ = CR; *b->last++ = LF;
+
+ b->last = ngx_cpymem(b->last, "SSL-Issuer-DN: ", sizeof("SSL-Issuer-DN: ") - 1);
+ b->last = ngx_copy(b->last, ssl_client_i_dn.data, ssl_client_i_dn.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
if (ahcf->header.len) {
b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
}
diff -r 4aa64f695031 -r 8744640301ae src/mail/ngx_mail_handler.c
--- a/src/mail/ngx_mail_handler.c Sat Jan 04 03:32:22 2014 +0400
+++ b/src/mail/ngx_mail_handler.c Mon Jan 13 11:02:55 2014 +0100
@@ -236,11 +236,40 @@
{
ngx_mail_session_t *s;
ngx_mail_core_srv_conf_t *cscf;
+ ngx_mail_ssl_conf_t *sslcf;

if (c->ssl->handshaked) {

s = c->data;

+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+ if (sslcf->verify != NGX_MAIL_SSL_VERIFY_OFF) {
+ long rc;
+ rc = SSL_get_verify_result(c->ssl->connection);
+
+ if (rc != X509_V_OK &&
+ (sslcf->verify != NGX_MAIL_SSL_VERIFY_OPTIONAL_NO_CA && ngx_ssl_verify_error_optional(rc))) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client SSL certificate verify error: (%l:%s)",
+ rc, X509_verify_cert_error_string(rc));
+ ngx_mail_close_connection(c);
+ return;
+ }
+
+ if (sslcf->verify == NGX_MAIL_SSL_VERIFY_ON) {
+ X509 *cert;
+ cert = SSL_get_peer_certificate(c->ssl->connection);
+
+ if (cert == NULL) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client sent no required SSL certificate");
+ ngx_mail_close_connection(c);
+ return;
+ }
+ X509_free(cert);
+ }
+ }
+
if (s->starttls) {
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

diff -r 4aa64f695031 -r 8744640301ae src/mail/ngx_mail_ssl_module.c
--- a/src/mail/ngx_mail_ssl_module.c Sat Jan 04 03:32:22 2014 +0400
+++ b/src/mail/ngx_mail_ssl_module.c Mon Jan 13 11:02:55 2014 +0100
@@ -43,6 +43,13 @@
{ ngx_null_string, 0 }
};

+static ngx_conf_enum_t ngx_mail_ssl_verify[] = {
+ { ngx_string("off"), NGX_MAIL_SSL_VERIFY_OFF },
+ { ngx_string("on"), NGX_MAIL_SSL_VERIFY_ON },
+ { ngx_string("optional"), NGX_MAIL_SSL_VERIFY_OPTIONAL },
+ { ngx_string("optional_no_ca"), NGX_MAIL_SSL_VERIFY_OPTIONAL_NO_CA },
+ { ngx_null_string, 0 }
+};

static ngx_command_t ngx_mail_ssl_commands[] = {

@@ -130,7 +137,40 @@
offsetof(ngx_mail_ssl_conf_t, session_timeout),
NULL },

- ngx_null_command
+ {
+ ngx_string("ssl_verify_client"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, verify),
+ &ngx_mail_ssl_verify
+ },
+ {
+ ngx_string("ssl_verify_depth"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_num_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, verify_depth),
+ NULL
+ },
+ {
+ ngx_string("ssl_client_certificate"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, client_certificate),
+ NULL
+ },
+ {
+ ngx_string("ssl_trusted_certificate"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, trusted_certificate),
+ NULL
+ },
+
+ ngx_null_command
};


@@ -184,6 +224,8 @@
* scf->ecdh_curve = { 0, NULL };
* scf->ciphers = { 0, NULL };
* scf->shm_zone = NULL;
+ * scf->client_certificate = { 0, NULL };
+ * scf->trusted_certificate = { 0, NULL };
*/

scf->enable = NGX_CONF_UNSET;
@@ -192,6 +234,8 @@
scf->builtin_session_cache = NGX_CONF_UNSET;
scf->session_timeout = NGX_CONF_UNSET;
scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
+ scf->verify = NGX_CONF_UNSET_UINT;
+ scf->verify_depth = NGX_CONF_UNSET_UINT;

return scf;
}
@@ -230,6 +274,11 @@

ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);

+ ngx_conf_merge_uint_value(conf->verify, prev->verify, NGX_MAIL_SSL_VERIFY_OFF);
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
+
+ ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, "");
+ ngx_conf_merge_str_value(conf->trusted_certificate, prev->trusted_certificate, "");

conf->ssl.log = cf->log;

@@ -310,6 +359,21 @@
return NGX_CONF_ERROR;
}

+ if (conf->verify) {
+ if (conf->client_certificate.len == 0 && conf->verify != NGX_MAIL_SSL_VERIFY_OPTIONAL_NO_CA) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no ssl_client_certificate for ssl_client_verify");
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_client_certificate(cf, &conf->ssl,
+ &conf->client_certificate,
+ conf->verify_depth)
+ != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (conf->prefer_server_ciphers) {
SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
}
diff -r 4aa64f695031 -r 8744640301ae src/mail/ngx_mail_ssl_module.h
--- a/src/mail/ngx_mail_ssl_module.h Sat Jan 04 03:32:22 2014 +0400
+++ b/src/mail/ngx_mail_ssl_module.h Mon Jan 13 11:02:55 2014 +0100
@@ -37,8 +37,14 @@
ngx_str_t dhparam;
ngx_str_t ecdh_curve;

+ ngx_str_t client_certificate;
+ ngx_str_t trusted_certificate;
+
ngx_str_t ciphers;

+ ngx_uint_t verify;
+ ngx_uint_t verify_depth;
+
ngx_shm_zone_t *shm_zone;

ngx_array_t *session_ticket_keys;
@@ -47,6 +53,13 @@
ngx_uint_t line;
} ngx_mail_ssl_conf_t;

+enum ngx_mail_ssl_verify_enum {
+ NGX_MAIL_SSL_VERIFY_OFF = 0,
+ NGX_MAIL_SSL_VERIFY_ON,
+ NGX_MAIL_SSL_VERIFY_OPTIONAL,
+ NGX_MAIL_SSL_VERIFY_OPTIONAL_NO_CA,
+};
+

extern ngx_module_t ngx_mail_ssl_module;


_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Sven Peter 1424 January 13, 2014 05:30AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Filipe Da Silva 441 January 13, 2014 07:10AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Sven Peter 407 January 13, 2014 08:12AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates Attachments

Sven Peter 564 January 13, 2014 10:30AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Maxim Dounin 439 January 14, 2014 07:10AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Sven Peter 486 January 14, 2014 08:42AM

Re: [PATCH] mail_{ssl, auth_http}_module: add support for SSL client certificates

Maxim Dounin 481 January 14, 2014 10:32AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 306
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready