Skip to content
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

[ADDED] TLS: natsOptions_TLSHandshakeFirst() #780

Merged
merged 2 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,12 @@ _checkForSecure(natsConnection *nc)
}

if ((s == NATS_OK) && nc->opts->secure)
s = _makeTLSConn(nc);
{
// If TLS handshake first is true, we have already done
// the handshake, so do it only if false.
if (!nc->opts->tlsHandshakeFirst)
s = _makeTLSConn(nc);
}

return NATS_UPDATE_ERR_STACK(s);
}
Expand Down Expand Up @@ -1968,8 +1973,14 @@ _processConnInit(natsConnection *nc)

nc->status = NATS_CONN_STATUS_CONNECTING;

// If we need to have a TLS connection and want the TLS handshake to occur
// first, do it now.
if (nc->opts->secure && nc->opts->tlsHandshakeFirst)
s = _makeTLSConn(nc);

// Process the INFO protocol that we should be receiving
s = _processExpectedInfo(nc);
if (s == NATS_OK)
s = _processExpectedInfo(nc);

// Send the CONNECT and PING protocol, and wait for the PONG.
if (s == NATS_OK)
Expand Down Expand Up @@ -3280,6 +3291,11 @@ natsConn_create(natsConnection **newConn, natsOptions *options)
nc->sockCtx.fd = NATS_SOCK_INVALID;
nc->opts = options;

// If the TLSHandshakeFirst option is specified, make sure that
// the Secure boolean is true.
if (nc->opts->tlsHandshakeFirst)
nc->opts->secure = true;

nc->errStr[0] = '\0';

s = natsMutex_Create(&(nc->mu));
Expand Down
21 changes: 19 additions & 2 deletions src/nats.h
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ typedef struct jsConsumerNamesList
*/
typedef struct jsConsumerPauseResponse
{
bool Paused;
bool Paused;
int64_t PauseUntil; ///< UTC time expressed as number of nanoseconds since epoch.
int64_t PauseRemaining; ///< Remaining time in nanoseconds.
} jsConsumerPauseResponse;
Expand Down Expand Up @@ -2327,6 +2327,23 @@ natsOptions_SetName(natsOptions *opts, const char *name);
NATS_EXTERN natsStatus
natsOptions_SetSecure(natsOptions *opts, bool secure);

/** \brief Performs TLS handshake first.
*
* If the server is not configured to require the client to perform
* the TLS handshake first, the server sends an INFO protocol first.
* When receiving it, the client and server are then initiate the
* TLS handshake.
*
* If the server is configured to require the client to perform
* the TLS handshake first, the client will fail to connect if
* not setting this option. Conversely, if the client is configured
* with this option but the server is not, the connection will fail.
*
* @param opts the pointer to the #natsOptions object.
*/
NATS_EXTERN natsStatus
natsOptions_TLSHandshakeFirst(natsOptions *opts);

/** \brief Loads the trusted CA certificates from a file.
*
* Loads the trusted CA certificates from a file.
Expand Down Expand Up @@ -4039,7 +4056,7 @@ natsConnection_Connect(natsConnection **nc, natsOptions *options);
* This means that all subscriptions and consumers should be resubscribed and
* their work resumed after successful reconnect where all reconnect options are
* respected.
*
*
* @param nc the pointer to the #natsConnection object.
*/
natsStatus
Expand Down
1 change: 1 addition & 0 deletions src/natsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ struct __natsOptions
bool pedantic;
bool allowReconnect;
bool secure;
bool tlsHandshakeFirst;
int ioBufSize;
int maxReconnect;
int64_t reconnectWait;
Expand Down
21 changes: 21 additions & 0 deletions src/opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,21 @@
return NATS_UPDATE_ERR_STACK(s);
}

natsStatus
natsOptions_TLSHandshakeFirst(natsOptions *opts)
{
natsStatus s = NATS_OK;

LOCK_AND_CHECK_OPTIONS(opts, 0);

opts->tlsHandshakeFirst = true;
opts->secure = true;

UNLOCK_OPTS(opts);

return NATS_UPDATE_ERR_STACK(s);

Check warning on line 378 in src/opts.c

View check run for this annotation

Codecov / codecov/patch

src/opts.c#L378

Added line #L378 was not covered by tests
}

natsStatus
natsOptions_LoadCATrustedCertificates(natsOptions *opts, const char *fileName)
{
Expand Down Expand Up @@ -689,6 +704,12 @@
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
}

natsStatus
natsOptions_TLSHandshakeFirst(natsOptions *opts)
{
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
}

natsStatus
natsOptions_LoadCATrustedCertificates(natsOptions *opts, const char *fileName)
{
Expand Down
1 change: 1 addition & 0 deletions test/list_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ _test(SSLBasic)
_test(SSLCertAndKeyFromMemory)
_test(SSLCiphers)
_test(SSLConnectVerboseOption)
_test(SSLHandshakeFirst)
_test(SSLLoadCAFromMemory)
_test(SSLMultithreads)
_test(SSLReconnectWithAuthError)
Expand Down
67 changes: 66 additions & 1 deletion test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2614,7 +2614,8 @@ void test_natsOptions(void)
&& (opts->writeDeadline == natsLib_defaultWriteDeadline())
&& !opts->noEcho
&& !opts->retryOnFailedConnect
&& !opts->ignoreDiscoveredServers)
&& !opts->ignoreDiscoveredServers
&& !opts->tlsHandshakeFirst);

test("Add URL: ");
s = natsOptions_SetURL(opts, "test");
Expand Down Expand Up @@ -2764,6 +2765,14 @@ void test_natsOptions(void)
testCond((s == NATS_ILLEGAL_STATE) && (opts->secure == false));
#endif

test("Set TLSHandshakeFirst: ");
s = natsOptions_TLSHandshakeFirst(opts);
#if defined(NATS_HAS_TLS)
testCond((s == NATS_OK) && (opts->tlsHandshakeFirst == true) && (opts->secure == true));
#else
testCond((s == NATS_ILLEGAL_STATE) && (opts->secure == false) && (opts->tlsHandshakeFirst == false));
#endif

test("Set Pedantic: ");
s = natsOptions_SetPedantic(opts, true);
testCond((s == NATS_OK) && (opts->pedantic == true));
Expand Down Expand Up @@ -21197,6 +21206,62 @@ void test_SSLConnectVerboseOption(void)
#endif
}

void test_SSLHandshakeFirst(void)
{
#if defined(NATS_HAS_TLS)
natsStatus s;
natsConnection *nc = NULL;
natsOptions *opts = NULL;
natsPid serverPid = NATS_INVALID_PID;

serverPid = _startServer("nats://127.0.0.1:4443", "-config tlsfirst.conf", true);
CHECK_SERVER_STARTED(serverPid);

test("Set options: ");
s = natsOptions_Create(&opts);
IFOK(s, natsOptions_SetURL(opts, "nats://127.0.0.1:4443"));
IFOK(s, natsOptions_SetSecure(opts, true));
IFOK(s, natsOptions_SkipServerVerification(opts, true));
IFOK(s, natsOptions_SetTimeout(opts, 500));
testCond(s == NATS_OK);

test("Check that connect fails if option not set: ");
s = natsConnection_Connect(&nc, opts);
testCond(s != NATS_OK);
nats_clearLastError();

test("Set TLSHandshakeFirst option error: ");
s = natsOptions_TLSHandshakeFirst(NULL);
testCond(s == NATS_INVALID_ARG);
nats_clearLastError();

test("Set TLSHandshakeFirst option: ");
s = natsOptions_TLSHandshakeFirst(opts);
testCond(s == NATS_OK);

test("Check that connect succeeds: ");
s = natsConnection_Connect(&nc, opts);
testCond(s == NATS_OK);
natsConnection_Destroy(nc);
nc = NULL;

_stopServer(serverPid);
serverPid = _startServer("nats://127.0.0.1:4443", "-config tls.conf", true);
CHECK_SERVER_STARTED(serverPid);

test("Check that connect fails if option is set but not in the server: ");
s = natsConnection_Connect(&nc, opts);
testCond(s != NATS_OK);
nats_clearLastError();

natsOptions_Destroy(opts);

#else
test("Skipped when built with no SSL support: ");
testCond(true);
#endif
}

#if defined(NATS_HAS_TLS)
static natsStatus
_elDummyAttach(void **userData, void *loop, natsConnection *nc, natsSock socket) { return NATS_OK; }
Expand Down
16 changes: 16 additions & 0 deletions test/tlsfirst.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

# Simple TLS config file

port: 4443
net: "0.0.0.0"

tls {
# Server cert
cert_file: "certs/server-cert.pem"
# Server private key
key_file: "certs/server-key.pem"
# Increase timeout for valgrind tests
timeout: 2
# Force client to do the handshake first
handshake_first: true
}
Loading