[PATCH] SSL support for the mail proxy module

Kunal Pariani kpariani at zimbra.com
Thu Oct 30 18:25:04 UTC 2014


Hello, 
Any reason for this patch not being committed upstream yet ? 

Thanks 
-Kunal 


From: "Franck Levionnois" <flevionnois at gmail.com> 
To: "nginx-devel" <nginx-devel at nginx.org>, "Kunal Pariani" <kpariani at zimbra.com> 
Sent: Tuesday, October 21, 2014 12:59:04 AM 
Subject: Re: [PATCH] SSL support for the mail proxy module 

Hello, 

The patch below has been submited some months ago. It do about the same, and it support to return a name by the auth script. 

Kind regards 
Franck Levionnois. 

---------- Forwarded message ---------- 
From: < flevionnois at gmail.com > 
Date: 2014-01-24 21:40 GMT+01:00 
Subject: [PATCH 1 of 1] Mail: added support for SSL client certificate 
To: nginx-devel at nginx.org 


# HG changeset patch 
# User Franck Levionnois < flevionnois at gmail.com > 
# Date 1390577176 -3600 
# Fri Jan 24 16:26:16 2014 +0100 
# Node ID d7b8381c200e300c2b6729574f4c2a 
b537804f56 
# Parent a387ce36744aa36b50e8171dbf01ef716748327e 
Mail: added support for SSL client certificate 

Add support for SSL module like HTTP. 

Added mail configuration directives (like http): 
ssl_verify_client, ssl_verify_depth, ssl_client_certificate, ssl_trusted_certificate, ssl_crl 

Added headers: 
Auth-Certificate, Auth-Certificate-Verify, Auth-Issuer-DN, Auth-Subject-DN, Auth-Subject-Serial 

diff -r a387ce36744a -r d7b8381c200e src/mail/ngx_mail_auth_http_module.c 
--- a/src/mail/ngx_mail_auth_http_module.c Thu Jan 23 22:09:59 2014 +0900 
+++ b/src/mail/ngx_mail_auth_http_module.c Fri Jan 24 16:26:16 2014 +0100 
@@ -1135,6 +1135,32 @@ 
"mail auth http dummy handler"); 
} 

+#if (NGX_MAIL_SSL) 
+static ngx_int_t 
+ngx_ssl_get_certificate_oneline(ngx_connection_t *c, ngx_pool_t *pool, 
+ ngx_str_t *b64_cert) 
+{ 
+ ngx_str_t pemCert; 
+ if (ngx_ssl_get_raw_certificate(c, pool, &pemCert) != NGX_OK) { 
+ return NGX_ERROR; 
+ } 
+ 
+ if (pemCert.len == 0) { 
+ b64_cert->len = 0; 
+ return NGX_OK; 
+ } 
+ 
+ b64_cert->len = ngx_base64_encoded_length(pemCert.len); 
+ b64_cert->data = ngx_palloc( pool, b64_cert->len); 
+ if (b64_cert->data == NULL) { 
+ b64_cert->len = 0; 
+ return NGX_ERROR; 
+ } 
+ ngx_encode_base64(b64_cert, &pemCert); 
+ 
+ return NGX_OK; 
+} 
+#endif 

static ngx_buf_t * 
ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, 
@@ -1142,7 +1168,9 @@ 
{ 
size_t len; 
ngx_buf_t *b; 
- ngx_str_t login, passwd; 
+ ngx_str_t login, passwd, client_cert, client_verify, 
+ client_subject, client_issuer, 
+ client_serial; 
ngx_mail_core_srv_conf_t *cscf; 

if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) { 
@@ -1155,6 +1183,42 @@ 

cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 

+#if (NGX_MAIL_SSL) 
+ if (s->connection->ssl) { 
+ if (ngx_ssl_get_client_verify(s->connection, pool, 
+ &client_verify) != NGX_OK) { 
+ return NULL; 
+ } 
+ 
+ if (ngx_ssl_get_subject_dn(s->connection, pool, 
+ &client_subject) != NGX_OK) { 
+ return NULL; 
+ } 
+ 
+ if (ngx_ssl_get_issuer_dn(s->connection, pool, 
+ &client_issuer) != NGX_OK) { 
+ return NULL; 
+ } 
+ 
+ if (ngx_ssl_get_serial_number(s->connection, pool, 
+ &client_serial) != NGX_OK) { 
+ return NULL; 
+ } 
+ 
+ if (ngx_ssl_get_certificate_oneline(s->connection, pool, 
+ &client_cert) != NGX_OK) { 
+ return NULL; 
+ } 
+ } else { 
+ client_verify.len = 0; 
+ client_issuer.len = 0; 
+ client_subject.len = 0; 
+ client_serial.len = 0; 
+ client_cert.len = 0; 
+ } 
+ 
+#endif 
+ 
len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 
+ sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1 
+ sizeof("Auth-Method: ") - 1 
@@ -1163,6 +1227,18 @@ 
+ sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1 
+ sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1 
+ sizeof("Auth-Salt: ") - 1 + s->salt.len 
+#if (NGX_MAIL_SSL) 
+ + sizeof("Auth-Certificate: ") - 1 + client_cert.len 
+ + sizeof(CRLF) - 1 
+ + sizeof("Auth-Certificate-Verify: ") - 1 + client_verify.len 
+ + sizeof(CRLF) - 1 
+ + sizeof("Auth-Issuer-DN: ") - 1 + client_issuer.len 
+ + sizeof(CRLF) - 1 
+ + sizeof("Auth-Subject-DN: ") - 1 + client_subject.len 
+ + sizeof(CRLF) - 1 
+ + sizeof("Auth-Subject-Serial: ") - 1 + client_serial.len 
+ + sizeof(CRLF) - 1 
+#endif 
+ sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len 
+ sizeof(CRLF) - 1 
+ sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN 
@@ -1212,7 +1288,43 @@ 

s->passwd.data = NULL; 
} 
- 
+#if (NGX_MAIL_SSL) 
+ if ( client_cert.len ) 
+ { 
+ b->last = ngx_cpymem(b->last, "Auth-Certificate: ", 
+ sizeof("Auth-Certificate: ") - 1); 
+ b->last = ngx_copy(b->last, client_cert.data, client_cert.len); 
+ *b->last++ = CR; *b->last++ = LF; 
+ } 
+ if ( client_verify.len ) 
+ { 
+ b->last = ngx_cpymem(b->last, "Auth-Certificate-Verify: ", 
+ sizeof("Auth-Certificate-Verify: ") - 1); 
+ b->last = ngx_copy(b->last, client_verify.data, client_verify.len); 
+ *b->last++ = CR; *b->last++ = LF; 
+ } 
+ if ( client_issuer.len ) 
+ { 
+ b->last = ngx_cpymem(b->last, "Auth-Issuer-DN: ", 
+ sizeof("Auth-Issuer-DN: ") - 1); 
+ b->last = ngx_copy(b->last, client_issuer.data, client_issuer.len); 
+ *b->last++ = CR; *b->last++ = LF; 
+ } 
+ if ( client_subject.len ) 
+ { 
+ b->last = ngx_cpymem(b->last, "Auth-Subject-DN: ", 
+ sizeof("Auth-Subject-DN: ") - 1); 
+ b->last = ngx_copy(b->last, client_subject.data, client_subject.len); 
+ *b->last++ = CR; *b->last++ = LF; 
+ } 
+ if ( client_serial.len ) 
+ { 
+ b->last = ngx_cpymem(b->last, "Auth-Subject-Serial: ", 
+ sizeof("Auth-Subject-Serial: ") - 1); 
+ b->last = ngx_copy(b->last, client_serial.data, client_serial.len); 
+ *b->last++ = CR; *b->last++ = LF; 
+ } 
+#endif 
b->last = ngx_cpymem(b->last, "Auth-Protocol: ", 
sizeof("Auth-Protocol: ") - 1); 
b->last = ngx_cpymem(b->last, cscf->protocol->name.data, 
diff -r a387ce36744a -r d7b8381c200e src/mail/ngx_mail_handler.c 
--- a/src/mail/ngx_mail_handler.c Thu Jan 23 22:09:59 2014 +0900 
+++ b/src/mail/ngx_mail_handler.c Fri Jan 24 16:26:16 2014 +0100 
@@ -236,11 +236,59 @@ 
{ 
ngx_mail_session_t *s; 
ngx_mail_core_srv_conf_t *cscf; 
+#if (NGX_MAIL_SSL) 
+ ngx_mail_ssl_conf_t *sslcf; 
+#endif 
+ 
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, 
+ "ngx_mail_ssl_handshake_handler handshaked: %d ", 
+ c->ssl->handshaked ); 

if (c->ssl->handshaked) { 

s = c->data; 

+#if (NGX_MAIL_SSL) 
+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); 
+ if (sslcf->verify) { 
+ long rc; 
+ 
+ rc = SSL_get_verify_result(c->ssl->connection); 
+ 
+ if (rc != X509_V_OK 
+ && (sslcf->verify != 3 || !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_ssl_remove_cached_session(sslcf->ssl.ctx, 
+ (SSL_get0_session(c->ssl->connection))); 
+ 
+ ngx_mail_close_connection(c); 
+ return; 
+ } 
+ 
+ if (sslcf->verify == 1) { 
+ 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_ssl_remove_cached_session(sslcf->ssl.ctx, 
+ (SSL_get0_session(c->ssl->connection))); 
+ 
+ ngx_mail_close_connection(c); 
+ return; 
+ } 
+ 
+ X509_free(cert); 
+ } 
+ } 
+#endif 
+ 
if (s->starttls) { 
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 

@@ -276,6 +324,10 @@ 

s->protocol = cscf->protocol->type; 

+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, 
+ "ngx_mail_init_session protocol: %d ", 
+ cscf->protocol->type ); 
+ 
s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module); 
if (s->ctx == NULL) { 
ngx_mail_session_internal_server_error(s); 
diff -r a387ce36744a -r d7b8381c200e src/mail/ngx_mail_ssl_module.c 
--- a/src/mail/ngx_mail_ssl_module.c Thu Jan 23 22:09:59 2014 +0900 
+++ b/src/mail/ngx_mail_ssl_module.c Fri Jan 24 16:26:16 2014 +0100 
@@ -43,6 +43,13 @@ 
{ ngx_null_string, 0 } 
}; 

+static ngx_conf_enum_t ngx_mail_ssl_verify[] = { 
+ { ngx_string("off"), 0 }, 
+ { ngx_string("on"), 1 }, 
+ { ngx_string("optional"), 2 }, 
+ { ngx_string("optional_no_ca"), 3 }, 
+ { ngx_null_string, 0 } 
+}; 

static ngx_command_t ngx_mail_ssl_commands[] = { 

@@ -102,6 +109,34 @@ 
offsetof(ngx_mail_ssl_conf_t, ciphers), 
NULL }, 

+ { 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_string("ssl_prefer_server_ciphers"), 
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, 
ngx_conf_set_flag_slot, 
@@ -137,6 +172,13 @@ 
offsetof(ngx_mail_ssl_conf_t, session_timeout), 
NULL }, 

+ { ngx_string("ssl_crl"), 
+ 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, crl), 
+ NULL }, 
+ 
ngx_null_command 
}; 

@@ -196,6 +238,8 @@ 
scf->enable = NGX_CONF_UNSET; 
scf->starttls = NGX_CONF_UNSET_UINT; 
scf->prefer_server_ciphers = NGX_CONF_UNSET; 
+ scf->verify = NGX_CONF_UNSET_UINT; 
+ scf->verify_depth = NGX_CONF_UNSET_UINT; 
scf->builtin_session_cache = NGX_CONF_UNSET; 
scf->session_timeout = NGX_CONF_UNSET; 
scf->session_tickets = NGX_CONF_UNSET; 
@@ -228,11 +272,20 @@ 
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1 
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); 

+ ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); 
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); 
+ 
ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); 
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); 

ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); 

+ ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, 
+ ""); 
+ ngx_conf_merge_str_value(conf->trusted_certificate, 
+ prev->trusted_certificate, ""); 
+ ngx_conf_merge_str_value(conf->crl, prev->crl, ""); 
+ 
ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, 
NGX_DEFAULT_ECDH_CURVE); 

@@ -318,6 +371,35 @@ 
return NGX_CONF_ERROR; 
} 

+ if (conf->verify) { 
+ 
+ if (conf->client_certificate.len == 0 && conf->verify != 3) { 
+ 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 (ngx_ssl_trusted_certificate(cf, &conf->ssl, 
+ &conf->trusted_certificate, 
+ conf->verify_depth) 
+ != NGX_OK) 
+ { 
+ return NGX_CONF_ERROR; 
+ } 
+ 
+ if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != 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 a387ce36744a -r d7b8381c200e src/mail/ngx_mail_ssl_module.h 
--- a/src/mail/ngx_mail_ssl_module.h Thu Jan 23 22:09:59 2014 +0900 
+++ b/src/mail/ngx_mail_ssl_module.h Fri Jan 24 16:26:16 2014 +0100 
@@ -28,6 +28,8 @@ 
ngx_uint_t starttls; 
ngx_uint_t protocols; 

+ ngx_uint_t verify; 
+ ngx_uint_t verify_depth; 
ssize_t builtin_session_cache; 

time_t session_timeout; 
@@ -36,6 +38,9 @@ 
ngx_str_t certificate_key; 
ngx_str_t dhparam; 
ngx_str_t ecdh_curve; 
+ ngx_str_t client_certificate; 
+ ngx_str_t trusted_certificate; 
+ ngx_str_t crl; 

ngx_str_t ciphers; 

2014-09-17 2:23 GMT+02:00 Kunal Pariani < kpariani at zimbra.com > : 


I guess these diffs can still be applied with limitation of having the same ssl setting for all upstreams until the support to return a name by the auth script is added later ? 

Thanks 
-Kunal 

----- Original Message ----- 
From: "Maxim Dounin" < mdounin at mdounin.ru > 
To: "nginx-devel" < nginx-devel at nginx.org > 
Sent: Tuesday, September 16, 2014 5:03:06 AM 
Subject: Re: [PATCH] SSL support for the mail proxy module 

Hello! 

On Tue, Sep 16, 2014 at 02:30:17AM -0500, Kunal Pariani wrote: 

> Updated the diffs after addressing the first 2 issues. 
> Regarding the 3rd comment, you are correct. Only 1 set of ssl 
> settings for all the mail backends with my patch. I guess this 
> will be a limitation with the current mail proxy workflow ? Am 
> not sure of the exact changes that will be required to address 
> this issue completely. 

Probably, returning a name by the auth script is a way to go. 

-- 
Maxim Dounin 
http://nginx.org/ 

_______________________________________________ 
nginx-devel mailing list 
nginx-devel at nginx.org 
http://mailman.nginx.org/mailman/listinfo/nginx-devel 

_______________________________________________ 
nginx-devel mailing list 
nginx-devel at nginx.org 
http://mailman.nginx.org/mailman/listinfo/nginx-devel 




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20141030/5ecda3a5/attachment-0001.html>


More information about the nginx-devel mailing list