Skip to content

Add SSL cert validation callback#826

Merged
levb merged 2 commits into
nats-io:mainfrom
ckasabula:ck/ssl_verification_callback_take2
Jan 30, 2025
Merged

Add SSL cert validation callback#826
levb merged 2 commits into
nats-io:mainfrom
ckasabula:ck/ssl_verification_callback_take2

Conversation

@ckasabula

Copy link
Copy Markdown
Contributor

No description provided.

@ckasabula
ckasabula force-pushed the ck/ssl_verification_callback_take2 branch from ea88eca to 8df350f Compare December 12, 2024 23:30
@ckasabula

Copy link
Copy Markdown
Contributor Author

@levb @mtmk Different approach this time based on your comments in my previous PR. This time exposing native, openssl verification callback. Smaller PR and no abstractions for cert, chain.

@ckasabula

Copy link
Copy Markdown
Contributor Author

@levb @mtmk Thoughts on this PR?

@kozlovic kozlovic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@levb @mtmk We may reconsider the abstraction to avoid all the requested changes, but if not, then the mentioned changes here would be required to compile and generate proper documentation.

Comment thread src/nats.h
@@ -2594,6 +2594,8 @@ natsOptions_SetExpectedHostname(natsOptions *opts, const char *hostname);
* By default, the server certificate is verified. You can disable the verification

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am not sure what the discussion you had with @levb and @mtmk was, but I think your first approach may have been a bit better with the abstraction.

This PR would not compile as-is. You would need to add at the top of this file something like:

#if defined(NATS_HAS_TLS)
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#endif

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also, in CMakeLists.txt of examples, examples/getstarted, examples/stan and test/dylib directories, you would need to add:

if(NATS_BUILD_WITH_TLS)
  include_directories(${OPENSSL_INCLUDE_DIR})
endif(NATS_BUILD_WITH_TLS)

so that those can be built with the openssl include directory.

Comment thread src/nats.h Outdated
Comment on lines +2607 to +2608
typedef struct x509_store_ctx_st X509_STORE_CTX;
typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remove those 2 lines. This would cause errors otherwise saying that you are redefining them.

Comment thread src/nats.h Outdated

typedef struct x509_store_ctx_st X509_STORE_CTX;
typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This whole function would need to be protected by the #if defined(NATS_HAS_TLS) / #endif because of SSL_verify_cb symbol.

Comment thread src/natsp.h
Comment thread src/opts.c
Comment thread src/nats.h
*/
NATS_EXTERN natsStatus
natsOptions_SetSSLVerificationCallback(natsOptions *opts, SSL_verify_cb callback);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This option will not show-up in the generated documentation as it stands. We would need to add to DoxyFile.NATS.Client.in:

diff --git a/doc/DoxyFile.NATS.Client.in b/doc/DoxyFile.NATS.Client.in
index be4b3485..8d70f132 100644
--- a/doc/DoxyFile.NATS.Client.in
+++ b/doc/DoxyFile.NATS.Client.in
@@ -2279,7 +2279,8 @@ INCLUDE_FILE_PATTERNS  =
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 PREDEFINED             = BUILD_IN_DOXYGEN \
-                         @NATS_DOC_INCLUDE_STREAMING@
+                         @NATS_DOC_INCLUDE_STREAMING@ \
+                         @NATS_DOC_INCLUDE_TLS@
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
 # tag can be used to specify a list of macro names that should be expanded. The

and in the main CMakeLists.txt:

iMacSynadia:build ivan$ git diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 413e0523..534de81e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -246,6 +246,7 @@ if(NATS_BUILD_WITH_TLS)
   if(NATS_BUILD_TLS_FORCE_HOST_VERIFY)
     add_definitions(-DNATS_FORCE_HOST_VERIFICATION)
   endif(NATS_BUILD_TLS_FORCE_HOST_VERIFY)
+  set(NATS_DOC_INCLUDE_TLS "NATS_HAS_TLS")
 endif(NATS_BUILD_WITH_TLS)

When generating docs, it will update the file DoxyFile.NATS.Client:

diff --git a/doc/DoxyFile.NATS.Client b/doc/DoxyFile.NATS.Client
index 2157d431..acd3a0c6 100644
--- a/doc/DoxyFile.NATS.Client
+++ b/doc/DoxyFile.NATS.Client
@@ -2279,7 +2279,8 @@ INCLUDE_FILE_PATTERNS  =
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 PREDEFINED             = BUILD_IN_DOXYGEN \
-                         NATS_HAS_STREAMING
+                         NATS_HAS_STREAMING \
+                         NATS_HAS_TLS
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
 # tag can be used to specify a list of macro names that should be expanded. The

@ckasabula

Copy link
Copy Markdown
Contributor Author

@kozlovic

@levb @mtmk We may reconsider the abstraction to avoid all the requested changes, but if not, then the mentioned changes here would be required to compile and generate proper documentation.

This was the original PR w/ the abstraction for cert and cert chain:
#825

@ckasabula

Copy link
Copy Markdown
Contributor Author

@kozlovic I went with the abstraction originally so the client wouldn't need to include openssl headers and link w/ openssl.

@kozlovic

Copy link
Copy Markdown
Member

@kozlovic I went with the abstraction originally so the client wouldn't need to include openssl headers and link w/ openssl.

Not sure what you mean by the client but the library does include and link with openssl, and the application would too, but it would be indirectly indeed.

@kozlovic

Copy link
Copy Markdown
Member

I will let @levb and @mtmk have a look and decide what is the next step.

@ckasabula

Copy link
Copy Markdown
Contributor Author

@kozlovic I mean the code/application that uses the library.

@kozlovic I went with the abstraction originally so the client wouldn't need to include openssl headers and link w/ openssl.

Not sure what you mean by the client but the library does include and link with openssl, and the application would too, but it would be indirectly indeed.

@ckasabula

Copy link
Copy Markdown
Contributor Author

@kozlovic I believe I have addressed your comments. I also updated the docs, which resulted in a lot of diffs. Let me know what you think.

@kozlovic kozlovic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please review my 2 comments and remove the last commit that updated the "doc/html". This will be done automatically if/when the PR is merged.

Comment thread doc/DoxyFile.NATS.Client.in
Comment thread src/nats.h
Comment thread examples/getstarted/CMakeLists.txt
@ckasabula
ckasabula force-pushed the ck/ssl_verification_callback_take2 branch 3 times, most recently from 562bfe6 to d030d1d Compare January 7, 2025 14:55
@ckasabula
ckasabula force-pushed the ck/ssl_verification_callback_take2 branch from d030d1d to 316ea64 Compare January 7, 2025 16:54

@kozlovic kozlovic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we are going with this approach, then LGTM, but will let @levb and @mtmk decide if this should be merged or not.

@mtmk

mtmk commented Jan 30, 2025

Copy link
Copy Markdown
Member

LGTM thanks @ckasabula (sorry for getting back to you late)

... just a couple of general comments mostly to share what I learned about using the OpenSSL apis. will leave the last word to @levb

Usage

API wise it's pretty simple:

#include <nats.h>

int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
  // good example in test.c
  return 1;
}

natsOptions_SetSSLVerificationCallback(opts, verify_callback);

Callback definition comes from OpenSSL but I think that's practical enough since we have to expose X509_STORE_CTX which is part of OpenSSL anyway. nice and simple.

Comparison to Other Libraries

For comparison I had a quick look at curl api which looks somewhat similar except they provide a callback to setup SSL_CTX where then you can assign the callback hooking into SSL_CTX_set_verify() rather than SSL_set_verify() which is what we're using internally per connection.

#include <curl/curl.h>
#include <openssl/ssl.h>

int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
  // same as above
  return 1;
}

CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) {
    SSL_CTX *ctx = (SSL_CTX *)sslctx;

    SSL_CTX_set_verify((SSL_CTX *)sslctx, SSL_VERIFY_PEER, verify_callback);

    return CURLE_OK;
}

curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctx_function);

Notably, different to curl api, we are calling SSL_set_verify() every time we reconnect which might be seen as unnecessary, since we can't swap out the callback between reconnects. I don't think there is a use case to change callbacks in between reconnects, so it's not really an issue.

In my opinion with, this PR we are introducing a simple way of setting the callback up and if/when needed, in a follow up PR or in the future we might want to consider exposing a callback to setup SSL_CTX similar to curl during the connection creation phase.

@levb levb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @ckasabula for your contribution and persistence, and everyone for the reviews/inputs!

@levb
levb merged commit c4565fc into nats-io:main Jan 30, 2025
@ckasabula

Copy link
Copy Markdown
Contributor Author

Thanks everyone.

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.

4 participants