diff --git a/examples/client/client.c b/examples/client/client.c index fc8e1276c..5ca2b7fba 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -328,6 +328,99 @@ int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, return EXIT_SUCCESS; } +const char* starttlsCmd[6] = { + "220", + "EHLO mail.example.com\r\n", + "250", + "STARTTLS\r\n", + "220", + "QUIT\r\n", +}; + +int StartTLS_Init(SOCKET_T* sockfd) +{ + char tmpBuf[256]; + + if (sockfd == NULL) + return BAD_FUNC_ARG; + + /* S: 220 SMTP service ready */ + if (read(*sockfd, tmpBuf, sizeof(tmpBuf)) < 0) + err_sys("failed to read STARTTLS command\n"); + + if (!XSTRNCMP(tmpBuf, starttlsCmd[0], XSTRLEN(starttlsCmd[0]))) { + printf("%s\n", tmpBuf); + XMEMSET(tmpBuf, 0, sizeof(tmpBuf)); + } else { + err_sys("incorrect STARTTLS command received"); + } + + /* C: EHLO mail.example.com */ + if (write(*sockfd, starttlsCmd[1], XSTRLEN(starttlsCmd[1])) != + (int)XSTRLEN(starttlsCmd[1])) + err_sys("failed to send STARTTLS EHLO command\n"); + + /* S: 250 offers a warm hug of welcome */ + if (read(*sockfd, tmpBuf, sizeof(tmpBuf)) < 0) + err_sys("failed to read STARTTLS command\n"); + + if (!XSTRNCMP(tmpBuf, starttlsCmd[2], XSTRLEN(starttlsCmd[2]))) { + printf("%s\n", tmpBuf); + XMEMSET(tmpBuf, 0, sizeof(tmpBuf)); + } else { + err_sys("incorrect STARTTLS command received"); + } + + /* C: STARTTLS */ + if (write(*sockfd, starttlsCmd[3], XSTRLEN(starttlsCmd[3])) != + (int)XSTRLEN(starttlsCmd[3])) { + err_sys("failed to send STARTTLS command\n"); + } + + /* S: 220 Go ahead */ + if (read(*sockfd, tmpBuf, sizeof(tmpBuf)) < 0) + err_sys("failed to read STARTTLS command\n"); + + if (!XSTRNCMP(tmpBuf, starttlsCmd[4], XSTRLEN(starttlsCmd[4]))) { + printf("%s\n", tmpBuf); + XMEMSET(tmpBuf, 0, sizeof(tmpBuf)); + } else { + err_sys("incorrect STARTTLS command received, expected 220"); + } + + return SSL_SUCCESS; +} + +int SMTP_Shutdown(WOLFSSL* ssl, int wc_shutdown) +{ + int ret; + char tmpBuf[256]; + + if (ssl == NULL) + return BAD_FUNC_ARG; + + printf("\nwolfSSL client shutting down SMTP connection\n"); + + XMEMSET(tmpBuf, 0, sizeof(tmpBuf)); + + /* C: QUIT */ + if (wolfSSL_write(ssl, starttlsCmd[5], (int)XSTRLEN(starttlsCmd[5])) != + (int)XSTRLEN(starttlsCmd[5])) + err_sys("failed to send SMTP QUIT command\n"); + + /* S: 221 2.0.0 Service closing transmission channel */ + if (wolfSSL_read(ssl, tmpBuf, sizeof(tmpBuf)) < 0) + err_sys("failed to read SMTP closing down response\n"); + + printf("%s\n", tmpBuf); + + ret = wolfSSL_shutdown(ssl); + if (wc_shutdown && ret == SSL_SHUTDOWN_NOT_DONE) + wolfSSL_shutdown(ssl); /* bidirectional shutdown */ + + return SSL_SUCCESS; +} + static void Usage(void) { @@ -364,6 +457,7 @@ static void Usage(void) printf("-N Use Non-blocking sockets\n"); printf("-r Resume session\n"); printf("-w Wait for bidirectional shutdown\n"); + printf("-M Use STARTTLS, using protocol (smtp)\n"); #ifdef HAVE_SECURE_RENEGOTIATION printf("-R Allow Secure Renegotiation\n"); printf("-i Force client Initiated Secure Renegotiation\n"); @@ -465,6 +559,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) const char* ourCert = cliCert; const char* ourKey = cliKey; + int doSTARTTLS = 0; + char* starttlsProt = NULL; + #ifdef WOLFSSL_TRUST_PEER_CERT const char* trustCert = NULL; #endif @@ -521,7 +618,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifndef WOLFSSL_VXWORKS while ((ch = mygetopt(argc, argv, - "?gdeDusmNrwRitfxXUPCVh:p:v:l:A:c:k:Z:b:zS:F:L:ToO:aB:W:E:")) != -1) { + "?gdeDusmNrwRitfxXUPCVh:p:v:l:A:c:k:Z:b:zS:F:L:ToO:aB:W:E:M:")) + != -1) { switch (ch) { case '?' : Usage(); @@ -762,6 +860,17 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + case 'M' : + doSTARTTLS = 1; + starttlsProt = myoptarg; + + if (XSTRNCMP(starttlsProt, "smtp", 4) != 0) { + Usage(); + exit(MY_EX_USAGE); + } + + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1163,6 +1272,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (wolfSSL_set_fd(ssl, sockfd) != SSL_SUCCESS) { err_sys("error in setting fd"); } + + /* STARTTLS */ + if (doSTARTTLS) { + if (StartTLS_Init(&sockfd) != SSL_SUCCESS) { + err_sys("error during STARTTLS protocol"); + } + } + #ifdef HAVE_CRL if (disableCRL == 0) { if (wolfSSL_EnableCRL(ssl, WOLFSSL_CRL_CHECKALL) != SSL_SUCCESS) @@ -1225,6 +1342,22 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif showPeer(ssl); + if (doSTARTTLS) { + if (XSTRNCMP(starttlsProt, "smtp", 4) == 0) { + if (SMTP_Shutdown(ssl, wc_shutdown) != SSL_SUCCESS) { + err_sys("error closing STARTTLS connection"); + } + } + + wolfSSL_free(ssl); + CloseSocket(sockfd); + + wolfSSL_CTX_free(ctx); + + ((func_args*)args)->return_code = 0; + return 0; + } + #ifdef HAVE_ALPN if (alpnList != NULL) { char *protocol_name = NULL; diff --git a/examples/client/client.h b/examples/client/client.h index 6b5bd27e4..913339ac0 100644 --- a/examples/client/client.h +++ b/examples/client/client.h @@ -35,6 +35,12 @@ int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port, int ClientBenchmarkThroughput(WOLFSSL_CTX* ctx, char* host, word16 port, int doDTLS, int throughput); +/* Initiates the STARTTLS command sequence over TCP */ +int StartTLS_Init(SOCKET_T* sockfd); + +/* Closes down the SMTP connection */ +int SMTP_Shutdown(WOLFSSL* ssl, int wc_shutdown); + #endif /* WOLFSSL_CLIENT_H */