Mercurial > hg > nginx
diff src/mail/ngx_mail_auth_http_module.c @ 5989:ec01b1d1fff1
Mail: client SSL certificates support.
The "ssl_verify_client", "ssl_verify_depth", "ssl_client_certificate",
"ssl_trusted_certificate", and "ssl_crl" directives introduced to control
SSL client certificate verification in mail proxy module.
If there is a certificate, detail of the certificate are passed to
the auth_http script configured via Auth-SSL-Verify, Auth-SSL-Subject,
Auth-SSL-Issuer, Auth-SSL-Serial, Auth-SSL-Fingerprint headers. If
the auth_http_pass_client_cert directive is set, client certificate
in PEM format will be passed in the Auth-SSL-Cert header (urlencoded).
If there is no required certificate provided during an SSL handshake
or certificate verification fails then a protocol-specific error is
returned after the SSL handshake and the connection is closed.
Based on previous work by Sven Peter, Franck Levionnois and Filipe Da Silva.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 25 Feb 2015 17:48:05 +0300 |
parents | 3b3f789655dc |
children | 6a7c6973d6fc |
line wrap: on
line diff
--- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -16,6 +16,7 @@ typedef struct { ngx_addr_t *peer; ngx_msec_t timeout; + ngx_flag_t pass_client_cert; ngx_str_t host_header; ngx_str_t uri; @@ -106,6 +107,13 @@ static ngx_command_t ngx_mail_auth_http 0, NULL }, + { ngx_string("auth_http_pass_client_cert"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_auth_http_conf_t, pass_client_cert), + NULL }, + ngx_null_command }; @@ -1143,6 +1151,11 @@ ngx_mail_auth_http_create_request(ngx_ma size_t len; ngx_buf_t *b; ngx_str_t login, passwd; +#if (NGX_MAIL_SSL) + ngx_str_t verify, subject, issuer, serial, fingerprint, + raw_cert, cert; + ngx_connection_t *c; +#endif ngx_mail_core_srv_conf_t *cscf; if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) { @@ -1153,6 +1166,61 @@ ngx_mail_auth_http_create_request(ngx_ma return NULL; } +#if (NGX_MAIL_SSL) + + c = s->connection; + + if (c->ssl) { + + /* certificate details */ + + if (ngx_ssl_get_client_verify(c, pool, &verify) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_subject_dn(c, pool, &subject) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_issuer_dn(c, pool, &issuer) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_serial_number(c, pool, &serial) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_fingerprint(c, pool, &fingerprint) != NGX_OK) { + return NULL; + } + + if (ahcf->pass_client_cert) { + + /* certificate itself, if configured */ + + if (ngx_ssl_get_raw_certificate(c, pool, &raw_cert) != NGX_OK) { + return NULL; + } + + if (ngx_mail_auth_http_escape(pool, &raw_cert, &cert) != NGX_OK) { + return NULL; + } + + } else { + ngx_str_null(&cert); + } + + } else { + ngx_str_null(&verify); + ngx_str_null(&subject); + ngx_str_null(&issuer); + ngx_str_null(&serial); + ngx_str_null(&fingerprint); + ngx_str_null(&cert); + } + +#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 @@ -1175,6 +1243,13 @@ ngx_mail_auth_http_create_request(ngx_ma + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1 #if (NGX_MAIL_SSL) + sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1 #endif + ahcf->header.len + sizeof(CRLF) - 1; @@ -1260,9 +1335,49 @@ ngx_mail_auth_http_create_request(ngx_ma #if (NGX_MAIL_SSL) - if (s->connection->ssl) { + if (c->ssl) { b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, sizeof("Auth-SSL: on" CRLF) - 1); + + b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ", + sizeof("Auth-SSL-Verify: ") - 1); + b->last = ngx_copy(b->last, verify.data, verify.len); + *b->last++ = CR; *b->last++ = LF; + + if (subject.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Subject: ", + sizeof("Auth-SSL-Subject: ") - 1); + b->last = ngx_copy(b->last, subject.data, subject.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (issuer.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Issuer: ", + sizeof("Auth-SSL-Issuer: ") - 1); + b->last = ngx_copy(b->last, issuer.data, issuer.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (serial.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Serial: ", + sizeof("Auth-SSL-Serial: ") - 1); + b->last = ngx_copy(b->last, serial.data, serial.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (fingerprint.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Fingerprint: ", + sizeof("Auth-SSL-Fingerprint: ") - 1); + b->last = ngx_copy(b->last, fingerprint.data, fingerprint.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (cert.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Cert: ", + sizeof("Auth-SSL-Cert: ") - 1); + b->last = ngx_copy(b->last, cert.data, cert.len); + *b->last++ = CR; *b->last++ = LF; + } } #endif @@ -1328,6 +1443,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_ } ahcf->timeout = NGX_CONF_UNSET_MSEC; + ahcf->pass_client_cert = NGX_CONF_UNSET; ahcf->file = cf->conf_file->file.name.data; ahcf->line = cf->conf_file->line; @@ -1363,6 +1479,8 @@ ngx_mail_auth_http_merge_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_value(conf->pass_client_cert, prev->pass_client_cert, 0); + if (conf->headers == NULL) { conf->headers = prev->headers; conf->header = prev->header;