[PATCH] Mail: added support for SSL client certificate

Franck Levionnois flevionnois at gmail.com
Fri Feb 21 11:46:10 UTC 2014


Hello,

I've forgotten to use the raw certificate and escape it. I'll re-submit
Thanks to Filipe for the review.

Franck.


2014-02-21 11:11 GMT+01:00 <flevionnois at gmail.com>:

> # HG changeset patch
> # User Franck Levionnois <flevionnois at gmail.com>
> # Date 1390577176 -3600
> #      Fri Jan 24 16:26:16 2014 +0100
> # Node ID 0a3fd2d54154c3d56131ee5053df0939db32d7b4
> # Parent  4dee5ad51e9e5b49085011e8785001e2d6c02b0d
> Mail: added support for SSL client certificate.
>
> Add support for SSL Mutual Authentification like in mail module.
>
> Added mail configuration directives (like http):
> ssl_verify_client, ssl_verify_depth,  ssl_client_certificate,
> ssl_trusted_certificate, ssl_crl.
>
> Added http auth headers:
> Auth-Certificate, Auth-Verify, Auth-Issuer-DN, Auth-Subject-DN,
> Auth-Subject-Serial.
>
> diff -r 4dee5ad51e9e -r 0a3fd2d54154 src/mail/ngx_mail_auth_http_module.c
> --- a/src/mail/ngx_mail_auth_http_module.c      Thu Feb 20 13:48:40 2014
> +0400
> +++ b/src/mail/ngx_mail_auth_http_module.c      Fri Jan 24 16:26:16 2014
> +0100
> @@ -1143,6 +1143,9 @@ 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                  cert, verify, subject, issuer, serial;
> +#endif
>      ngx_mail_core_srv_conf_t  *cscf;
>
>      if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
> @@ -1155,6 +1158,41 @@ ngx_mail_auth_http_create_request(ngx_ma
>
>      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, &verify) !=
> NGX_OK)
> +        {
> +            return NULL;
> +        }
> +
> +        if (ngx_ssl_get_subject_dn(s->connection, pool,
> +                                   &subject) != NGX_OK) {
> +            return NULL;
> +        }
> +
> +        if (ngx_ssl_get_issuer_dn(s->connection, pool,
> +                                  &issuer) != NGX_OK) {
> +            return NULL;
> +        }
> +
> +        if (ngx_ssl_get_serial_number(s->connection, pool,
> +                                      &serial) != NGX_OK) {
> +            return NULL;
> +        }
> +
> +        if (ngx_ssl_get_certificate(s->connection, pool,
> +                                    &cert) != NGX_OK) {
> +            return NULL;
> +        }
> +    } else {
> +        verify.len = 0;
> +        issuer.len = 0;
> +        subject.len = 0;
> +        serial.len = 0;
> +        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 +1201,14 @@ ngx_mail_auth_http_create_request(ngx_ma
>            + 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 + cert.len + sizeof(CRLF) - 1
> +          + sizeof("Auth-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1
> +          + sizeof("Auth-Issuer-DN: ") - 1 + issuer.len + sizeof(CRLF) - 1
> +          + sizeof("Auth-Subject-DN: ") - 1 + subject.len + sizeof(CRLF)
> - 1
> +          + sizeof("Auth-Subject-Serial: ") - 1 + 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
> @@ -1213,6 +1259,44 @@ ngx_mail_auth_http_create_request(ngx_ma
>          s->passwd.data = NULL;
>      }
>
> +#if (NGX_MAIL_SSL)
> +    if (cert.len) {
> +        b->last = ngx_cpymem(b->last, "Auth-Certificate: ",
> +                             sizeof("Auth-Certificate: ") - 1);
> +        b->last = ngx_copy(b->last, cert.data, cert.len);
> +        *b->last++ = CR; *b->last++ = LF;
> +    }
> +
> +    if (verify.len) {
> +        b->last = ngx_cpymem(b->last, "Auth-Verify: ",
> +                             sizeof("Auth-Verify: ") - 1);
> +        b->last = ngx_copy(b->last, verify.data, verify.len);
> +        *b->last++ = CR; *b->last++ = LF;
> +    }
> +
> +    if (issuer.len) {
> +        b->last = ngx_cpymem(b->last, "Auth-Issuer-DN: ",
> +                             sizeof("Auth-Issuer-DN: ") - 1);
> +        b->last = ngx_copy(b->last, issuer.data, issuer.len);
> +        *b->last++ = CR; *b->last++ = LF;
> +    }
> +
> +    if (subject.len) {
> +        b->last = ngx_cpymem(b->last, "Auth-Subject-DN: ",
> +                             sizeof("Auth-Subject-DN: ") - 1);
> +        b->last = ngx_copy(b->last, subject.data, subject.len);
> +        *b->last++ = CR; *b->last++ = LF;
> +    }
> +
> +    if (serial.len) {
> +        b->last = ngx_cpymem(b->last, "Auth-Subject-Serial: ",
> +                             sizeof("Auth-Subject-Serial: ") - 1);
> +        b->last = ngx_copy(b->last, serial.data, 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 4dee5ad51e9e -r 0a3fd2d54154 src/mail/ngx_mail_handler.c
> --- a/src/mail/ngx_mail_handler.c       Thu Feb 20 13:48:40 2014 +0400
> +++ b/src/mail/ngx_mail_handler.c       Fri Jan 24 16:26:16 2014 +0100
> @@ -236,11 +236,60 @@ ngx_mail_ssl_handshake_handler(ngx_conne
>  {
>      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);
>
> diff -r 4dee5ad51e9e -r 0a3fd2d54154 src/mail/ngx_mail_ssl_module.c
> --- a/src/mail/ngx_mail_ssl_module.c    Thu Feb 20 13:48:40 2014 +0400
> +++ b/src/mail/ngx_mail_ssl_module.c    Fri Jan 24 16:26:16 2014 +0100
> @@ -43,6 +43,14 @@ static ngx_conf_bitmask_t  ngx_mail_ssl_
>      { 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 +110,34 @@ static ngx_command_t  ngx_mail_ssl_comma
>        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_TAKE1,
> +      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 +173,13 @@ static ngx_command_t  ngx_mail_ssl_comma
>        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
>  };
>
> @@ -189,6 +232,9 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
>       *     scf->certificate_key = { 0, NULL };
>       *     scf->dhparam = { 0, NULL };
>       *     scf->ecdh_curve = { 0, NULL };
> +     *     scf->client_certificate = { 0, NULL };
> +     *     scf->trusted_certificate = { 0, NULL };
> +     *     scf->crl = { 0, NULL };
>       *     scf->ciphers = { 0, NULL };
>       *     scf->shm_zone = NULL;
>       */
> @@ -196,6 +242,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
>      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 +276,20 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf,
>                           (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 +375,35 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf,
>          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 4dee5ad51e9e -r 0a3fd2d54154 src/mail/ngx_mail_ssl_module.h
> --- a/src/mail/ngx_mail_ssl_module.h    Thu Feb 20 13:48:40 2014 +0400
> +++ b/src/mail/ngx_mail_ssl_module.h    Fri Jan 24 16:26:16 2014 +0100
> @@ -28,6 +28,8 @@ typedef struct {
>      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 @@ typedef struct {
>      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;
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20140221/59c66243/attachment-0001.html>


More information about the nginx-devel mailing list