diff --git a/src/conn.c b/src/conn.c index 54bb697dd..37fcc1790 100644 --- a/src/conn.c +++ b/src/conn.c @@ -737,6 +737,13 @@ _makeTLSConn(natsConnection *nc) SSL_set_verify(ssl, SSL_VERIFY_PEER, _collectSSLErr); } } +#if defined(NATS_USE_OPENSSL_1_1) + // add the host name in the SNI extension + if ((s == NATS_OK) && (nc->cur != NULL) && (!SSL_set_tlsext_host_name(ssl, nc->cur->url->host))) + { + s = nats_setError(NATS_SSL_ERROR, "unable to set SNI extension for hostname '%s'", nc->cur->url->host); + } +#endif if ((s == NATS_OK) && (SSL_do_handshake(ssl) != 1)) { s = nats_setError(NATS_SSL_ERROR, diff --git a/test/list_test.txt b/test/list_test.txt index b53816d54..496d5b3f8 100644 --- a/test/list_test.txt +++ b/test/list_test.txt @@ -247,6 +247,7 @@ _test(SSLCertAndKeyFromMemory) _test(SSLCiphers) _test(SSLConnectVerboseOption) _test(SSLHandshakeFirst) +_test(SSLServerNameIndication) _test(SSLLoadCAFromMemory) _test(SSLMultithreads) _test(SSLReconnectWithAuthError) diff --git a/test/test.c b/test/test.c index a7aa56118..5f2965a61 100644 --- a/test/test.c +++ b/test/test.c @@ -21347,6 +21347,84 @@ void test_SSLHandshakeFirst(void) #endif } +void test_SSLServerNameIndication(void) +{ +#if defined(NATS_HAS_TLS) + natsStatus s = NATS_OK; + natsSock sock = NATS_SOCK_INVALID; + natsThread *t = NULL; + struct threadArg arg; + natsSockCtx ctx; + static const char *server = "tls://localhost:4222"; + + memset(&ctx, 0, sizeof(natsSockCtx)); + + s = _createDefaultThreadArgsForCbTests(&arg); + IFOK(s, natsOptions_Create(&(arg.opts))); + IFOK(s, natsOptions_SetSecure(arg.opts, true)); + IFOK(s, natsOptions_TLSHandshakeFirst(arg.opts)); + IFOK(s, natsOptions_SetServers(arg.opts, &server, 1)); + if (s != NATS_OK) + FAIL("@@ Unable to setup test!"); + + test("Start server and connect client: ") + + arg.control = 3; + + s = _startMockupServer(&sock, "localhost", "4222"); + + // Start the thread that will try to connect to our server... + IFOK(s, natsThread_Create(&t, _connectToMockupServer, (void*) &arg)); + + if ((s == NATS_OK) + && (((ctx.fd = accept(sock, NULL, NULL)) == NATS_SOCK_INVALID) + || natsSock_SetCommonTcpOptions(ctx.fd) != NATS_OK)) + { + s = NATS_SYS_ERROR; + } + + testCond((s == NATS_OK) && (ctx.fd > 0)); + + test("Read ClientHello from client: "); + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + + int size = recv(ctx.fd, buffer, sizeof(buffer), 0); + testCond(size > 0); + + // remove all null chars to allow the use of strstr on the result + for (int i = 0; i < size; ++i) { + if (buffer[i] == 0) + buffer[i] = '0'; + } + + test("Check hostname is found in ClientHello: "); + bool found = strstr(buffer, "localhost"); +#if defined(NATS_USE_OPENSSL_1_1) + testCond(found == true); +#else + testCond(found == false); +#endif + + // Need to close those for the client side to unblock. + natsSock_Close(ctx.fd); + natsSock_Close(sock); + + // Wait for the client to finish. + if (t != NULL) + { + natsThread_Join(t); + natsThread_Destroy(t); + } + + _destroyDefaultThreadArgs(&arg); + +#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; }