Thanks to visit codestin.com
Credit goes to github.com

Skip to content

SSL: optional ssl_client_certificate for ssl_verify_client. #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2024

Conversation

praveen-li
Copy link
Contributor

@praveen-li praveen-li commented Sep 9, 2024

Starting from TLSv1.1 (as seen since draft-ietf-tls-rfc2246-bis-00),
the "certificate_authorities" field grammar of the CertificateRequest
message was redid to allow no distinguished names. In TLSv1.3, with
the restructured CertificateRequest message, this can be similarly
done by optionally including the "certificate_authorities" extension.
This allows to avoid sending DNs at all.

In practice, aside from published TLS specifications, all supported
SSL/TLS libraries allow to request client certificates with an empty
DN list for any protocol version. For instance, when operating in
TLSv1, this results in sending the "certificate_authorities" list as
a zero-length vector, which corresponds to the TLSv1.1 specification.
Such behaviour goes back to SSLeay.

The change relaxes the requirement to specify at least one trusted CA
certificate in the ssl_client_certificate directive, which resulted in
sending DNs of these certificates (closes #142). Instead, all trusted
CA certificates can be specified now using the ssl_trusted_certificate
directive if needed. A notable difference that certificates specified
in ssl_trusted_certificate are always loaded remains (see 3648ba.)

Proposed changes

As per below RFCs, ssl_client_certificate should be optional with TLS1.1+ when ssl_verify_client is configured as on/optional:

TLS1.3: rfc8446#section-4.2.4:

 The server MAY send it(CA) in the  CertificateRequest message.

TLS1.2: rfc5246#section-7.4.4:

If the certificate_authorities list is empty, then the client MAY send any certificate of the appropriate ClientCertificateType, unless there is some external arrangement to the contrary.

TLS1.1: rfc4346#section-7.4.4: Similar wording as TLS 1.2.

TLSv1.0: rfc2246#section-7.4.4: It was not clearly defined in v1.0, that CA list in certificate request message can be empty or not.

Also Nginx documentation seems to suggest the same:

The list of certificates will be sent to clients. If this is not desired, the [ssl_trusted_certificate] directive can be used."

**Tested with nginx-tests.

Verified after deploying on Debian.**

Relevant Config

       # Enable client certificate verification (mTLS)
        ssl_trusted_certificate /Users/pchere/Desktop/src_code/certs/ca.crt;  # CA cert for client certificates
        ssl_verify_client on;  # Force client certificate validation

With ssl_protocols TLSv1.2 TLSv1.3;

% sudo /usr/local/nginx/sbin/nginx -s reload

%curl -v --cert /Users/pchere/Desktop/src_code/certs/client.crt --key /Users/pchere/Desktop/src_code/certs/client.key --cacert /Users/pchere/Desktop/src_code/certs/ca.crt https://localhost/
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /Users/pchere/Desktop/src_code/certs/ca.crt
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, CERT verify (15):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted http/1.1

Comment ssl_trusted_certificate in nginx config.

 % sudo /usr/local/nginx/sbin/nginx -s reload
nginx: [emerg] no ssl_client_certificate or ssl_trusted_certificatefor ssl_verify_client

@praveen-li
Copy link
Contributor Author

@pluknet Kindly review this PR.

Many deployments may have dependency on a.) this fix and b.) client certificate validation with OCSP. Kindly let me know, if you recommend breaking this into http, mail and stream.

Thanks a ton in advance.

@praveen-li praveen-li changed the title SSL: Make ssl_client_certificate optional with TLSv1.1+. Closes #142. SSL: Make ssl_client_certificate optional with TLSv1.1+. Sep 11, 2024
@praveen-li praveen-li force-pushed the make_ssl_client_certificate_optional branch from 2efaba7 to 1d2a16a Compare September 15, 2024 17:28
@praveen-li
Copy link
Contributor Author

@arut

Hi Roman, It will be really helpful, if you can review this PR. We have a product, where we do not want to force user to configure the upper level config which maps to ssl_client_certificate in nginx for mTLS.

Considering, from TLS1.1+ (rfc4346#section-7.4.4), it is not mandatory to send 'CA Issuer names' in 'certificate request' message from server to client in case on mTLS. So, It will be great if we can make ssl_client_certificate directive optional when ssl_trusted_certificate is configured.

Thanks in advance for reviewing it.

@pluknet pluknet self-assigned this Sep 16, 2024
@pluknet
Copy link
Contributor

pluknet commented Sep 18, 2024

Suggested commit:

changeset:   143ac35cb (HEAD -> make_ssl_client_certificate_optional, sandbox/master)
user:        Sergey Kandaurov <[email protected]>
date:        Wed Sep 18 18:30:09 2024 +0400
description:
SSL: optional ssl_client_certificate for ssl_verify_client.

Starting from TLSv1.1 (as seen since draft-ietf-tls-rfc2246-bis-00),
the "certificate_authorities" field grammar of the CertificateRequest
message was redid to allow no distinguished names.  In TLSv1.3, with
the restructured CertificateRequest message, this can be similarly
done by optionally including the "certificate_authorities" extension.
This allows to avoid sending DNs at all.

In practice, aside from published TLS specifications, all supported
SSL/TLS libraries allow to request client certificates with an empty
DN list for any protocol version.  For instance, when operating in
TLSv1, this results in sending the "certificate_authorities" list as
a zero-length vector, which corresponds to the TLSv1.1 specification.
Such behaviour goes back to SSLeay.

The change relaxes the requirement to specify at least one trusted CA
certificate in the ssl_client_certificate directive, which resulted in
sending DNs of these certificates (closes #142).  Instead, all trusted
CA certificates can be specified now using the ssl_trusted_certificate
directive if needed.  A notable difference that certificates specified
in ssl_trusted_certificate are always loaded remains (see 3648ba7db).


diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 1c92d9fa8..abc8d49ab 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -787,9 +787,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index aebb4ccb6..b547dc101 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -450,9 +450,13 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 072e74917..0233a9258 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -1008,9 +1008,13 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 

@praveen-li praveen-li force-pushed the make_ssl_client_certificate_optional branch from 1d2a16a to 4ea80fa Compare September 18, 2024 21:09
@praveen-li praveen-li changed the title SSL: Make ssl_client_certificate optional with TLSv1.1+. SSL: optional ssl_client_certificate for ssl_verify_client. Sep 18, 2024
@praveen-li praveen-li force-pushed the make_ssl_client_certificate_optional branch 2 times, most recently from 949d98e to 7344f88 Compare September 18, 2024 21:24
@praveen-li
Copy link
Contributor Author

Suggested commit:

changeset:   143ac35cb (HEAD -> make_ssl_client_certificate_optional, sandbox/master)
user:        Sergey Kandaurov <[email protected]>
date:        Wed Sep 18 18:30:09 2024 +0400
description:
SSL: optional ssl_client_certificate for ssl_verify_client.

Starting from TLSv1.1 (as seen since draft-ietf-tls-rfc2246-bis-00),
the "certificate_authorities" field grammar of the CertificateRequest
message was redid to allow no distinguished names.  In TLSv1.3, with
the restructured CertificateRequest message, this can be similarly
done by optionally including the "certificate_authorities" extension.
This allows to avoid sending DNs at all.

In practice, aside from published TLS specifications, all supported
SSL/TLS libraries allow to request client certificates with an empty
DN list for any protocol version.  For instance, when operating in
TLSv1, this results in sending the "certificate_authorities" list as
a zero-length vector, which corresponds to the TLSv1.1 specification.
Such behaviour goes back to SSLeay.

The change relaxes the requirement to specify at least one trusted CA
certificate in the ssl_client_certificate directive, which resulted in
sending DNs of these certificates (closes #142).  Instead, all trusted
CA certificates can be specified now using the ssl_trusted_certificate
directive if needed.  A notable difference that certificates specified
in ssl_trusted_certificate are always loaded remains (see 3648ba7db).


diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 1c92d9fa8..abc8d49ab 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -787,9 +787,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index aebb4ccb6..b547dc101 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -450,9 +450,13 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 072e74917..0233a9258 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -1008,9 +1008,13 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->verify) {
 
-        if (conf->client_certificate.len == 0 && conf->verify != 3) {
+        if (conf->verify != 3
+            && conf->client_certificate.len == 0
+            && conf->trusted_certificate.len == 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_verify_client");
+                          "no ssl_client_certificate or "
+                          "ssl_trusted_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 

@pluknet Agree with the suggested commit as mentioned in thread. Pushed the same commit. Kindly review and merge. Thanks again.

@praveen-li praveen-li requested a review from pluknet September 18, 2024 21:45
@pluknet pluknet requested a review from arut September 19, 2024 10:26
@pluknet
Copy link
Contributor

pluknet commented Sep 19, 2024

Over to @arut for the second review.

Starting from TLSv1.1 (as seen since draft-ietf-tls-rfc2246-bis-00),
the "certificate_authorities" field grammar of the CertificateRequest
message was redone to allow no distinguished names.  In TLSv1.3, with
the restructured CertificateRequest message, this can be similarly
done by optionally including the "certificate_authorities" extension.
This allows to avoid sending DNs at all.

In practice, aside from published TLS specifications, all supported
SSL/TLS libraries allow to request client certificates with an empty
DN list for any protocol version.  For instance, when operating in
TLSv1, this results in sending the "certificate_authorities" list as
a zero-length vector, which corresponds to the TLSv1.1 specification.
Such behaviour goes back to SSLeay.

The change relaxes the requirement to specify at least one trusted CA
certificate in the ssl_client_certificate directive, which resulted in
sending DNs of these certificates (closes nginx#142).  Instead, all trusted
CA certificates can be specified now using the ssl_trusted_certificate
directive if needed.  A notable difference that certificates specified
in ssl_trusted_certificate are always loaded remains (see 3648ba7).

Co-authored-by: Praveen Chaudhary <[email protected]>
Copy link
Contributor

@arut arut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redid -> redone in the commit log.
Otherwise looks ok.

@pluknet pluknet force-pushed the make_ssl_client_certificate_optional branch from 7344f88 to 7a59f43 Compare September 20, 2024 10:14
@pluknet
Copy link
Contributor

pluknet commented Sep 20, 2024

Addressed review comments.

@arut arut merged commit 18afcda into nginx:master Sep 20, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ssl_client_certificate should be optional with TLS1.1+
3 participants