diff --git a/examples/client/client.c b/examples/client/client.c index 3e96ce539..5755e022d 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -141,6 +141,7 @@ static void Usage(void) printf("-m Match domain name in cert\n"); printf("-N Use Non-blocking sockets\n"); printf("-r Resume session\n"); + printf("-w Wait for bidirectional shutdown\n"); #ifdef HAVE_SECURE_RENEGOTIATION printf("-R Allow Secure Renegotiation\n"); printf("-i Force client Initiated Secure Renegotiation\n"); @@ -207,6 +208,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int doPeerCheck = 1; int nonBlocking = 0; int resumeSession = 0; + int shutdown = 0; int scr = 0; /* allow secure renegotiation */ int forceScr = 0; /* force client initiaed scr */ int trackMemory = 0; @@ -258,7 +260,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) StackTrap(); while ((ch = mygetopt(argc, argv, - "?gdDusmNrRitfxUPh:p:v:l:A:c:k:b:zS:L:ToO:a")) != -1) { + "?gdDusmNrwRitfxUPh:p:v:l:A:c:k:b:zS:L:ToO:a")) != -1) { switch (ch) { case '?' : Usage(); @@ -367,6 +369,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) resumeSession = 1; break; + case 'w' : + shutdown = 1; + break; + case 'R' : #ifdef HAVE_SECURE_RENEGOTIATION scr = 1; @@ -643,7 +649,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (wolfSSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed"); - wolfSSL_shutdown(ssl); + if (shutdown) { /* bidirectional shutdown if true */ + if (!wolfSSL_shutdown(ssl)) + wolfSSL_shutdown(ssl); + } + else { + wolfSSL_shutdown(ssl); + } wolfSSL_free(ssl); CloseSocket(sockfd); } @@ -802,8 +814,15 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif - if (doDTLS == 0) /* don't send alert after "break" command */ - wolfSSL_shutdown(ssl); /* echoserver will interpret as new conn */ + if (doDTLS == 0) { /* don't send alert after "break" command */ + if (shutdown) { /* bidirectional shutdown if true */ + if (!wolfSSL_shutdown(ssl)) /* echoserver interprets as new conn */ + wolfSSL_shutdown(ssl); + } + else { + wolfSSL_shutdown(ssl); + } + } #ifdef ATOMIC_USER if (atomicUser) FreeAtomicUser(ssl); @@ -879,7 +898,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) /* try to send session break */ wolfSSL_write(sslResume, msg, msgSz); - wolfSSL_shutdown(sslResume); + if (shutdown) { /* bidirectional shutdown if true */ + if (!wolfSSL_shutdown(sslResume)) + wolfSSL_shutdown(sslResume); + } + else { + wolfSSL_shutdown(sslResume); + } wolfSSL_free(sslResume); CloseSocket(sockfd); } diff --git a/examples/server/server.c b/examples/server/server.c index 8374d376d..a2c5d0176 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -135,6 +135,7 @@ static void Usage(void) printf("-r Create server ready file, for external monitor\n"); printf("-N Use Non-blocking sockets\n"); printf("-S Use Host Name Indication\n"); + printf("-w Wait for bidirectional shutdown\n"); #ifdef HAVE_OCSP printf("-o Perform OCSP lookup on peer certificate\n"); printf("-O Perform OCSP lookup using as responder\n"); @@ -173,6 +174,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int fewerPackets = 0; int pkCallbacks = 0; int serverReadyFile = 0; + int shutdown = 0; char* cipherList = NULL; const char* verifyCert = cliCert; const char* ourCert = svrCert; @@ -203,7 +205,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) fdOpenSession(Task_self()); #endif - while ((ch = mygetopt(argc, argv, "?dbstnNufraPp:v:l:A:c:k:S:oO:")) != -1) { + while ((ch = mygetopt(argc, argv, "?dbstnNufrawPp:v:l:A:c:k:S:oO:")) != -1) { switch (ch) { case '?' : Usage(); @@ -257,6 +259,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif break; + case 'w' : + shutdown = 1; + break; + case 'v' : version = atoi(myoptarg); if (version < 0 || version > 3) { @@ -560,7 +566,13 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) Task_yield(); #endif - SSL_shutdown(ssl); + if (shutdown) { /* bidirectional shutdown if true */ + if (!SSL_shutdown(ssl)) + SSL_shutdown(ssl); + } + else { + SSL_shutdown(ssl); + } SSL_free(ssl); SSL_CTX_free(ctx); diff --git a/src/internal.c b/src/internal.c index e43d35820..9833d7979 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6351,8 +6351,9 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type, WOLFSSL_MSG(" close notify"); ssl->options.closeNotify = 1; } - WOLFSSL_ERROR(*type); - + if (!ssl->options.sentNotify) { + WOLFSSL_ERROR(*type); + } if (ssl->keys.encryptionOn) { if (*inOutIdx + ssl->keys.padSz > totalSz) return BUFFER_E; @@ -7750,7 +7751,9 @@ startScr: while (ssl->buffers.clearOutputBuffer.length == 0) { if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); + if (!ssl->options.sentNotify) { + WOLFSSL_ERROR(ssl->error); + } if (ssl->error == ZERO_RETURN) { WOLFSSL_MSG("Zero return, no more data coming"); return 0; /* no more data coming */ diff --git a/src/ssl.c b/src/ssl.c index 8e0ae8a5e..5c61d6571 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -936,6 +936,17 @@ int wolfSSL_shutdown(WOLFSSL* ssl) return SSL_FATAL_ERROR; } ssl->options.sentNotify = 1; /* don't send close_notify twice */ + WOLFSSL_LEAVE("SSL_shutdown()", ssl->error); + return 0; + } + + /* call wolfSSL_shutdown again for bidirectional shudown */ + if (ssl->options.sentNotify && !ssl->options.closeNotify) { + ssl->error = ReceiveData(ssl, 0, 0, 0); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } } WOLFSSL_LEAVE("SSL_shutdown()", ssl->error);