diff --git a/examples/client/client.c b/examples/client/client.c index 4286c5306..eab3d10ce 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -72,15 +72,19 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl) { -#ifndef WOLFSSL_CALLBACKS - int ret = wolfSSL_connect(ssl); -#else - int ret = wolfSSL_connect_ex(ssl, handShakeCB, timeoutCB, timeout); -#endif - int error = wolfSSL_get_error(ssl, 0); - SOCKET_T sockfd = (SOCKET_T)wolfSSL_get_fd(ssl); + int ret; + int error; + SOCKET_T sockfd; int select_ret = 0; +#ifndef WOLFSSL_CALLBACKS + ret = wolfSSL_connect(ssl); +#else + ret = wolfSSL_connect_ex(ssl, handShakeCB, timeoutCB, timeout); +#endif + error = wolfSSL_get_error(ssl, 0); + sockfd = (SOCKET_T)wolfSSL_get_fd(ssl); + while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE || error == WC_PENDING_E)) { @@ -551,6 +555,60 @@ static int SMTP_Shutdown(WOLFSSL* ssl, int wc_shutdown) return SSL_SUCCESS; } +static void ClientWrite(WOLFSSL* ssl, char* msg, int msgSz) +{ + int ret, err; + char buffer[WOLFSSL_MAX_ERROR_SZ]; + + do { + err = 0; /* reset error */ + ret = wolfSSL_write(ssl, msg, msgSz); + if (ret <= 0) { + err = wolfSSL_get_error(ssl, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + #endif + } + } while (err == WC_PENDING_E); + if (ret != msgSz) { + printf("SSL_write msg error %d, %s\n", err, + wolfSSL_ERR_error_string(err, buffer)); + err_sys("SSL_write failed"); + } +} + +static void ClientRead(WOLFSSL* ssl, char* reply, int replyLen, int mustRead) +{ + int ret, err; + char buffer[WOLFSSL_MAX_ERROR_SZ]; + + do { + err = 0; /* reset error */ + ret = wolfSSL_read(ssl, reply, replyLen); + if (ret <= 0) { + err = wolfSSL_get_error(ssl, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + else + #endif + if (err != SSL_ERROR_WANT_READ) { + printf("SSL_read reply error %d, %s\n", err, + wolfSSL_ERR_error_string(err, buffer)); + err_sys("SSL_read failed"); + } + } + } while (err == WC_PENDING_E || (mustRead && err == SSL_ERROR_WANT_READ)); + if (ret > 0) { + reply[ret] = 0; + printf("%s\n", reply); + } +} static void Usage(void) { @@ -655,6 +713,9 @@ static void Usage(void) #ifdef HAVE_CURVE25519 printf("-t Use X25519 for key exchange\n"); #endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + printf("-Q Support requesting certificate post-handshake\n"); +#endif } THREAD_RETURN WOLFSSL_THREAD client_test(void* args) @@ -751,6 +812,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int helloRetry = 0; int onlyKeyShare = 0; int noPskDheKe = 0; +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + int postHandAuth = 0; +#endif #endif int updateKeysIVs = 0; @@ -797,10 +861,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) StackTrap(); #ifndef WOLFSSL_VXWORKS - /* Not used: t, Q */ + /* Not used: All used */ while ((ch = mygetopt(argc, argv, "?" "ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz" - "A:B:CDE:F:GHIJKL:M:NO:PRS:TUVW:XYZ:")) != -1) { + "A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:")) != -1) { switch (ch) { case '?' : Usage(); @@ -1107,6 +1171,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) case 't' : #ifdef HAVE_CURVE25519 useX25519 = 1; + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECC) + onlyKeyShare = 2; + #endif + #endif + break; + + case 'Q' : + #if defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_POST_HANDSHAKE_AUTH) + postHandAuth = 1; #endif break; @@ -1533,6 +1607,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (noPskDheKe) wolfSSL_CTX_no_dhe_psk(ctx); #endif + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (postHandAuth) + wolfSSL_CTX_allow_post_handshake_auth(ctx); + #endif ssl = wolfSSL_new(ctx); if (ssl == NULL) { @@ -1846,76 +1924,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_update_keys(ssl); #endif - do { - err = 0; /* reset error */ - ret = wolfSSL_write(ssl, msg, msgSz); - if (ret <= 0) { - err = wolfSSL_get_error(ssl, 0); - #ifdef WOLFSSL_ASYNC_CRYPT - if (err == WC_PENDING_E) { - ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); - if (ret < 0) break; - } - #endif - } - } while (err == WC_PENDING_E); - if (ret != msgSz) { - printf("SSL_write msg error %d, %s\n", err, - wolfSSL_ERR_error_string(err, buffer)); - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("SSL_write failed"); - } + ClientWrite(ssl, msg, msgSz); - do { - err = 0; /* reset error */ - ret = wolfSSL_read(ssl, reply, sizeof(reply)-1); - if (ret <= 0) { - err = wolfSSL_get_error(ssl, 0); - #ifdef WOLFSSL_ASYNC_CRYPT - if (err == WC_PENDING_E) { - ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); - if (ret < 0) break; - } - #endif - } - } while (err == WC_PENDING_E || err == SSL_ERROR_WANT_READ); - if (ret > 0) { - reply[ret] = 0; - printf("Server response: %s\n", reply); + ClientRead(ssl, reply, sizeof(reply)-1, 1); - if (sendGET) { /* get html */ - while (1) { - do { - err = 0; /* reset error */ - ret = wolfSSL_read(ssl, reply, sizeof(reply)-1); - if (ret <= 0) { - err = wolfSSL_get_error(ssl, 0); - #ifdef WOLFSSL_ASYNC_CRYPT - if (err == WC_PENDING_E) { - ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); - if (ret < 0) break; - } - #endif - } - } while (err == WC_PENDING_E); - if (ret > 0) { - reply[ret] = 0; - printf("%s\n", reply); - } - else - break; - } - } - } - if (ret < 0) { - if (err != SSL_ERROR_WANT_READ) { - printf("SSL_read reply error %d, %s\n", err, - wolfSSL_ERR_error_string(err, buffer)); - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - err_sys("SSL_read failed"); - } + if (sendGET) { /* get html */ + ClientRead(ssl, reply, sizeof(reply)-1, 0); } #ifndef NO_SESSION_CACHE diff --git a/examples/server/server.c b/examples/server/server.c index 766f1ea2f..28d527a55 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -240,6 +240,63 @@ int ServerEchoData(SSL* ssl, int clientfd, int echoData, int throughput) return EXIT_SUCCESS; } +static void ServerRead(WOLFSSL* ssl, char* input, int inputLen) +{ + int ret, err; + char buffer[CYASSL_MAX_ERROR_SZ]; + + /* Read data */ + do { + err = 0; /* reset error */ + ret = SSL_read(ssl, input, inputLen); + if (ret < 0) { + err = SSL_get_error(ssl, 0); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + else + #endif + if (err != SSL_ERROR_WANT_READ) { + printf("SSL_read input error %d, %s\n", err, + ERR_error_string(err, buffer)); + err_sys("SSL_read failed"); + } + } + } while (err == WC_PENDING_E); + if (ret > 0) { + input[ret] = 0; /* null terminate message */ + printf("Client message: %s\n", input); + } +} + +static void ServerWrite(WOLFSSL* ssl, const char* output, int outputLen) +{ + int ret, err; + char buffer[CYASSL_MAX_ERROR_SZ]; + + do { + err = 0; /* reset error */ + ret = SSL_write(ssl, output, outputLen); + if (ret <= 0) { + err = SSL_get_error(ssl, 0); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) break; + } + #endif + } + } while (err == WC_PENDING_E || err == SSL_ERROR_WANT_WRITE); + if (ret != outputLen) { + printf("SSL_write msg error %d, %s\n", err, + ERR_error_string(err, buffer)); + err_sys("SSL_write failed"); + } +} static void Usage(void) { @@ -307,6 +364,9 @@ static void Usage(void) #ifdef WOLFSSL_TLS13 printf("-K Key Exchange for PSK not using (EC)DHE\n"); printf("-U Update keys and IVs before sending\n"); +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + printf("-Q Request certificate from client post-handshake\n"); +#endif #endif } @@ -393,6 +453,9 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int noPskDheKe = 0; #endif int updateKeysIVs = 0; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + int postHandAuth = 0; +#endif #ifdef WOLFSSL_STATIC_MEMORY #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \ @@ -437,10 +500,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #ifdef WOLFSSL_VXWORKS useAnyAddr = 1; #else - /* Not Used: h, m, t, x, y, z, F, J, M, Q, T, V, W, X, Y */ + /* Not Used: h, m, t, x, y, z, F, J, M, T, V, W, X, Y */ while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:nop:q:rsuv:w" - "A:B:C:D:E:GHIKL:NO:PR:S:UYZ:")) != -1) { + "A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:")) != -1) { switch (ch) { case '?' : Usage(); @@ -654,6 +717,13 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif break; + case 'Q' : + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + postHandAuth = 1; + doCliCertCheck = 0; + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1180,40 +1250,43 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) free(list); } #endif + +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (postHandAuth) { + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | + ((usePskPlus)? SSL_VERIFY_FAIL_EXCEPT_PSK : + SSL_VERIFY_FAIL_IF_NO_PEER_CERT),0); + if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) + != SSL_SUCCESS) { + err_sys("can't load ca file, Please run from wolfSSL home dir"); + } + #ifdef WOLFSSL_TRUST_PEER_CERT + if (trustCert) { + if ((ret = wolfSSL_CTX_trust_peer_cert(ctx, trustCert, + SSL_FILETYPE_PEM)) != SSL_SUCCESS) { + err_sys("can't load trusted peer cert file"); + } + } + #endif /* WOLFSSL_TRUST_PEER_CERT */ + } + #endif +#endif + if (echoData == 0 && throughput == 0) { const char* write_msg; int write_msg_sz; - /* Read data */ - do { - err = 0; /* reset error */ - ret = SSL_read(ssl, input, sizeof(input)-1); - if (ret < 0) { - err = SSL_get_error(ssl, 0); - - #ifdef WOLFSSL_ASYNC_CRYPT - if (err == WC_PENDING_E) { - ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); - if (ret < 0) break; - } - else - #endif - if (err != SSL_ERROR_WANT_READ) { - printf("SSL_read input error %d, %s\n", err, - ERR_error_string(err, buffer)); - err_sys("SSL_read failed"); - } - } - } while (err == WC_PENDING_E); - if (ret > 0) { - input[ret] = 0; /* null terminate message */ - printf("Client message: %s\n", input); - } + ServerRead(ssl, input, sizeof(input)-1); #ifdef WOLFSSL_TLS13 if (updateKeysIVs) wolfSSL_update_keys(ssl); #endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (postHandAuth) + wolfSSL_request_certificate(ssl); +#endif /* Write data */ if (!useWebServerMsg) { @@ -1224,25 +1297,14 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) write_msg = webServerMsg; write_msg_sz = sizeof(webServerMsg); } - do { - err = 0; /* reset error */ - ret = SSL_write(ssl, write_msg, write_msg_sz); - if (ret <= 0) { - err = SSL_get_error(ssl, 0); + ServerWrite(ssl, write_msg, write_msg_sz); - #ifdef WOLFSSL_ASYNC_CRYPT - if (err == WC_PENDING_E) { - ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); - if (ret < 0) break; - } - #endif - } - } while (err == WC_PENDING_E || err == SSL_ERROR_WANT_WRITE); - if (ret != write_msg_sz) { - printf("SSL_write msg error %d, %s\n", err, - ERR_error_string(err, buffer)); - err_sys("SSL_write failed"); +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (postHandAuth) { + ServerWrite(ssl, write_msg, write_msg_sz); + ServerRead(ssl, input, sizeof(input)-1); } +#endif } else { ServerEchoData(ssl, clientfd, echoData, throughput); diff --git a/src/internal.c b/src/internal.c index 3bdf53e60..41532de90 100755 --- a/src/internal.c +++ b/src/internal.c @@ -4131,10 +4131,13 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->options.useClientOrder = ctx->useClientOrder; #ifdef WOLFSSL_TLS13 -#ifdef HAVE_SESSION_TICKET - ssl->options.noTicketTls13 = ctx->noTicketTls13; -#endif + #ifdef HAVE_SESSION_TICKET + ssl->options.noTicketTls13 = ctx->noTicketTls13; + #endif ssl->options.noPskDheKe = ctx->noPskDheKe; + #if defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ssl->options.postHandshakeAuth = ctx->postHandshakeAuth; + #endif #endif #ifdef HAVE_TLS_EXTENSIONS @@ -4628,6 +4631,14 @@ void SSL_ResourceFree(WOLFSSL* ssl) } #endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + while (ssl->certReqCtx != NULL) { + CertReqCtx* curr = ssl->certReqCtx; + ssl->certReqCtx = curr->next; + XFREE(curr, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + #ifdef WOLFSSL_STATIC_MEMORY /* check if using fixed io buffers and free them */ if (ssl->heap != NULL) { @@ -7533,13 +7544,35 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz } #endif #ifndef NO_WOLFSSL_SERVER - /* Must contain value sent in request when received from client. */ + /* Must contain value sent in request. */ if (ssl->options.side == WOLFSSL_SERVER_END) { - if (ssl->clientCertCtx.length != ctxSz || - XMEMCMP(ssl->clientCertCtx.buffer, - input + args->idx, ctxSz) != 0) { + if (ssl->options.handShakeState != HANDSHAKE_DONE && + ctxSz != 0) { return INVALID_CERT_CTX_E; } + else if (ssl->options.handShakeState == HANDSHAKE_DONE) { + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + CertReqCtx* curr = ssl->certReqCtx; + CertReqCtx* prev = NULL; + while (curr != NULL) { + if ((ctxSz == curr->len) && + XMEMCMP(&curr->ctx, input + args->idx, ctxSz) + == 0) { + if (prev != NULL) + prev->next = curr->next; + else + ssl->certReqCtx = curr->next; + XFREE(curr, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + break; + } + prev = curr; + curr = curr->next; + } + if (curr == NULL) + #endif + return INVALID_CERT_CTX_E; + } } #endif args->idx += ctxSz; @@ -13836,6 +13869,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case KEY_SHARE_ERROR: return "Key share extension did not contain a valid named group"; + case POST_HAND_AUTH_ERROR: + return "Client will not do post handshake authentication"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index a67836d15..1d65f2e6b 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -846,13 +846,25 @@ int wolfSSL_negotiate(WOLFSSL* ssl) WOLFSSL_ENTER("wolfSSL_negotiate"); #ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) - err = wolfSSL_accept(ssl); + if (ssl->options.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_accept_TLSv13(ssl); + else +#endif + err = wolfSSL_accept(ssl); + } #endif #ifndef NO_WOLFSSL_CLIENT - if (ssl->options.side == WOLFSSL_CLIENT_END) - err = wolfSSL_connect(ssl); + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_connect_TLSv13(ssl); + else +#endif + err = wolfSSL_connect(ssl); + } #endif WOLFSSL_LEAVE("wolfSSL_negotiate", err); diff --git a/src/tls.c b/src/tls.c index 23748f99c..0baec3ccf 100755 --- a/src/tls.c +++ b/src/tls.c @@ -6327,6 +6327,108 @@ int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes) #endif +/******************************************************************************/ +/* Post-Handshake Authentication */ +/******************************************************************************/ + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* Get the size of the encoded Post-Hanshake Authentication extension. + * Only in ClientHello. + * + * msgType The type of the message this extension is being written into. + * returns the number of bytes of the encoded key share extension. + */ +static word16 TLSX_PostHandAuth_GetSize(byte msgType) +{ + if (msgType == client_hello) + return OPAQUE8_LEN; + + return SANITY_MSG_E; +} + +/* Writes the Post-Handshake Authentication extension into the output buffer. + * Assumes that the the output buffer is big enough to hold data. + * Only in ClientHello. + * + * output The buffer to write into. + * msgType The type of the message this extension is being written into. + * returns the number of bytes written into the buffer. + */ +static word16 TLSX_PostHandAuth_Write(byte* output, byte msgType) +{ + if (msgType == client_hello) { + *output = 0; + return OPAQUE8_LEN; + } + + return SANITY_MSG_E; +} + +/* Parse the Post-Handshake Authentication extension. + * Only in ClientHello. + * + * ssl The SSL/TLS object. + * input The extension data. + * length The length of the extension data. + * msgType The type of the message this extension is being parsed from. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + byte len; + + if (msgType == client_hello) { + /* Ensure length byte exists. */ + if (length < OPAQUE8_LEN) + return BUFFER_E; + + len = input[0]; + if (length - OPAQUE8_LEN != len || len != 0) + return BUFFER_E; + + ssl->options.postHandshakeAuth = 1; + return 0; + } + + return SANITY_MSG_E; +} + +/* Create a new Post-handshake authentication object in the extensions. + * + * ssl The SSL/TLS object. + * returns 0 on success and other values indicate failure. + */ +static int TLSX_PostHandAuth_Use(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the PSK key exchange modes extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH); + if (extension == NULL) { + /* Push new Post-handshake Authentication extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_POST_HANDSHAKE_AUTH, NULL, + ssl->heap); + if (ret != 0) + return ret; + } + + return 0; +} + +#define PHA_GET_SIZE TLSX_PostHandAuth_GetSize +#define PHA_WRITE TLSX_PostHandAuth_Write +#define PHA_PARSE TLSX_PostHandAuth_Parse + +#else + +#define PHA_GET_SIZE(a) 0 +#define PHA_WRITE(a, b) 0 +#define PHA_PARSE(a, b, c, d) 0 + +#endif + /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -6412,6 +6514,11 @@ void TLSX_FreeAll(TLSX* list, void* heap) case TLSX_PSK_KEY_EXCHANGE_MODES: break; #endif + + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + break; + #endif #endif } @@ -6520,6 +6627,11 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) length += PKM_GET_SIZE(extension->val, msgType); break; #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + length += PHA_GET_SIZE(msgType); + break; + #endif #endif } @@ -6650,6 +6762,12 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += PKM_WRITE(extension->val, output + offset, msgType); break; #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + WOLFSSL_MSG("Post-Handshake Authentication extension to write"); + offset += PHA_WRITE(output + offset, msgType); + break; + #endif #endif } @@ -6949,7 +7067,8 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) - if (!ssl->options.userCurves && !ssl->ctx->userCurves) { + if (!ssl->options.userCurves && !ssl->ctx->userCurves && + TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) { #ifndef HAVE_FIPS #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES) #ifndef NO_ECC_SECP @@ -7045,10 +7164,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ - WOLFSSL_MSG("Adding signature algorithms extension"); - if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, - ssl->heap)) != 0) + WOLFSSL_MSG("Adding signature algorithms extension"); + if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, ssl->heap)) + != 0) { return ret; + } #ifdef WOLFSSL_TLS13 if (!isServer && IsAtLeastTLSv1_3(ssl->version)) { @@ -7059,7 +7179,9 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return ret; #ifdef HAVE_SUPPORTED_CURVES - if (!ssl->options.userCurves && !ssl->ctx->userCurves) { + if (!ssl->options.userCurves && !ssl->ctx->userCurves && + TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) + == NULL) { /* Add FFDHE supported groups. */ #ifdef HAVE_FFDHE_2048 ret = TLSX_UseSupportedCurve(&ssl->extensions, @@ -7096,33 +7218,33 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) #endif if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) { - #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ - !defined(NO_ECC_SECP) + #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP256R1, 0, NULL, NULL); - #elif defined(HAVE_CURVE25519) + #elif defined(HAVE_CURVE25519) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_X25519, 0, NULL, NULL); - #elif (!defined(NO_ECC384) || defined(HAVE_ALL_CURVES)) && \ - !defined(NO_ECC_SECP) + #elif (!defined(NO_ECC384) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP384R1, 0, NULL, NULL); - #elif (!defined(NO_ECC521) || defined(HAVE_ALL_CURVES)) && \ - !defined(NO_ECC_SECP) + #elif (!defined(NO_ECC521) || defined(HAVE_ALL_CURVES)) && \ + !defined(NO_ECC_SECP) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_ECC_SECP521R1, 0, NULL, NULL); - #elif defined(HAVE_FFDHE_2048) + #elif defined(HAVE_FFDHE_2048) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_2048, 0, NULL, NULL); - #elif defined(HAVE_FFDHE_3072) + #elif defined(HAVE_FFDHE_3072) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_3072, 0, NULL, NULL); - #elif defined(HAVE_FFDHE_4096) + #elif defined(HAVE_FFDHE_4096) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_4096, 0, NULL, NULL); - #elif defined(HAVE_FFDHE_6144) + #elif defined(HAVE_FFDHE_6144) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_6144, 0, NULL, NULL); - #elif defined(HAVE_FFDHE_8192) + #elif defined(HAVE_FFDHE_8192) ret = TLSX_KeyShare_Use(ssl, WOLFSSL_FFDHE_8192, 0, NULL, NULL); - #else + #else ret = KEY_SHARE_ERROR; - #endif + #endif if (ret != 0) return ret; } @@ -7187,6 +7309,13 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return ret; } #endif + #if defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (!isServer && ssl->options.postHandshakeAuth) { + ret = TLSX_PostHandAuth_Use(ssl); + if (ret != 0) + return ret; + } + #endif } #endif @@ -7673,6 +7802,20 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = PKM_PARSE(ssl, input + offset, size, msgType); break; #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + case TLSX_POST_HANDSHAKE_AUTH: + WOLFSSL_MSG("PSK Key Exchange Modes extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } + ret = PHA_PARSE(ssl, input + offset, size, msgType); + break; + #endif #endif } diff --git a/src/tls13.c b/src/tls13.c index 1261ceb72..bacdd9ac6 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -784,9 +784,9 @@ static const byte appTrafficLabel[APP_TRAFFIC_LABEL_SZ + 1] = static int DeriveTrafficSecret(WOLFSSL* ssl, byte* secret) { WOLFSSL_MSG("Derive New Application Traffic Secret"); - return DeriveKeyMsg(ssl, secret, -1, secret, - appTrafficLabel, APP_TRAFFIC_LABEL_SZ, - NULL, 0, ssl->specs.mac_algorithm); + return DeriveKey(ssl, secret, -1, secret, + appTrafficLabel, APP_TRAFFIC_LABEL_SZ, + ssl->specs.mac_algorithm, 0); } /* Derive the early secret using HKDF Extract. @@ -2607,10 +2607,13 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size) { - word16 len; - word32 begin = *inOutIdx; - int ret; - Suites peerSuites; + word16 len; + word32 begin = *inOutIdx; + int ret; + Suites peerSuites; +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + CertReqCtx* certReqCtx; +#endif WOLFSSL_ENTER("DoTls13CertificateRequest"); @@ -2629,14 +2632,21 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, if (ssl->options.connectState < FINISHED_DONE && len > 0) return BUFFER_ERROR; - /* Request context parsed here. */ - /* TODO: [TLS13] Request context for post-handshake auth. - * Store the value and return it in Certificate message. - * Must be unique in the scope of the connection. - */ +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + certReqCtx = XMALLOC(sizeof(CertReqCtx) + len - 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = len; + XMEMCPY(&certReqCtx->ctx, input + *inOutIdx, len); + ssl->certReqCtx = certReqCtx; +#endif *inOutIdx += len; - /* TODO: [TLS13] Add extension handling. */ + /* TODO: Add support for more extensions: + * signed_certificate_timestamp, certificate_authorities, oid_filters. + */ /* Certificate extensions */ if ((*inOutIdx - begin) + OPAQUE16_LEN > size) return BUFFER_ERROR; @@ -2644,6 +2654,8 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, *inOutIdx += OPAQUE16_LEN; if ((*inOutIdx - begin) + len > size) return BUFFER_ERROR; + if (len == 0) + return INVALID_PARAMETER; if ((ret = TLSX_Parse(ssl, (byte *)(input + *inOutIdx), len, certificate_request, &peerSuites))) return ret; @@ -2651,11 +2663,25 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, PickHashSigAlgo(ssl, peerSuites.hashSigAlgo, peerSuites.hashSigAlgoSz); - ssl->options.sendVerify = SEND_CERT; + if (ssl->buffers.certificate && ssl->buffers.certificate->buffer && + ssl->buffers.key && ssl->buffers.key->buffer) + ssl->options.sendVerify = SEND_CERT; + else + ssl->options.sendVerify = SEND_BLANK_CERT; /* This message is always encrypted so add encryption padding. */ *inOutIdx += ssl->keys.padSz; +#if !defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.side == WOLFSSL_CLIENT_END && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.connectState = FIRST_REPLY_DONE; + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + } +#endif + return ret; } @@ -2719,11 +2745,14 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, #ifdef HAVE_SESSION_TICKET /* Decode the identity. */ if ((ret = DoClientTicket(ssl, current->identity, current->identityLen)) == WOLFSSL_TICKET_RET_OK) { - /* Check the ticket isn't too old or new. */ - int diff = TimeNowInMilliseconds() - ssl->session.ticketSeen; + word32 now = TimeNowInMilliseconds(); + int diff = now - ssl->session.ticketSeen; diff -= current->ticketAge - ssl->session.ticketAdd; - /* TODO: [TLS13] What should the value be? Configurable? */ - if (diff < -1000 || diff > 1000) { + /* Check session and ticket age timeout. + * Allow +/- 1000 milliseconds on ticket age. + */ + if ((ssl->session.bornOn + ssl->session.timeout) * 1000 >= now || + diff < -1000 || diff - MAX_TICKET_AGE_SECS * 1000 > 1000) { /* Invalid difference, fallback to full handshake. */ ssl->options.resuming = 0; break; @@ -3268,15 +3297,16 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) * This message is always encrypted in TLS v1.3. * Only a server will send this message. * - * ssl The SSL/TLS object. + * ssl SSL/TLS object. + * reqCtx Request context. + * reqCtxLen Length of context. 0 when sending as part of handshake. * returns 0 on success, otherwise failure. */ -int SendTls13CertificateRequest(WOLFSSL* ssl) +int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, int reqCtxLen) { byte* output; int ret; int sendSz; - int reqCtxLen = 0; word32 i; int reqSz; @@ -3305,10 +3335,11 @@ int SendTls13CertificateRequest(WOLFSSL* ssl) AddTls13Headers(output, reqSz, certificate_request, ssl); /* Certificate request context. */ - /* TODO: [TLS13] Request context for post-handshake auth. - * Must be unique in the scope of the connection. - */ output[i++] = reqCtxLen; + if (reqCtxLen != 0) { + XMEMCPY(output + i, reqCtx, reqCtxLen); + i += reqCtxLen; + } /* Certificate extensions. */ i += TLSX_WriteResponse(ssl, output + i, certificate_request); @@ -3801,12 +3832,17 @@ int SendTls13Certificate(WOLFSSL* ssl) word32 idx = 0; word32 offset = OPAQUE16_LEN; byte* p = NULL; + byte certReqCtxLen = 0; + byte* certReqCtx = NULL; WOLFSSL_ENTER("SendTls13Certificate"); - /* TODO: [TLS13] Request context for post-handshake auth. - * Taken from request if post-handshake. - */ +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + certReqCtxLen = ssl->certReqCtx->len; + certReqCtx = &ssl->certReqCtx->ctx; + } +#endif if (ssl->options.sendVerify == SEND_BLANK_CERT) { certSz = 0; @@ -3822,8 +3858,9 @@ int SendTls13Certificate(WOLFSSL* ssl) } /* Certificate Data */ certSz = ssl->buffers.certificate->length; - /* Cert Req Ctx Len | Cert List Len | Cert Data Len */ - headerSz = OPAQUE8_LEN + CERT_HEADER_SZ + CERT_HEADER_SZ; + /* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */ + headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ + + CERT_HEADER_SZ; /* Length of message data with one certificate and empty extensions. */ length = headerSz + certSz + OPAQUE16_LEN; /* Length of list data with one certificate and empty extensions. */ @@ -3892,9 +3929,13 @@ int SendTls13Certificate(WOLFSSL* ssl) AddTls13FragHeaders(output, fragSz, 0, payloadSz, certificate, ssl); /* Request context. */ - output[i++] = 0; - length -= 1; - fragSz -= 1; + output[i++] = certReqCtxLen; + if (certReqCtxLen > 0) { + XMEMCPY(output + i, certReqCtx, certReqCtxLen); + i += certReqCtxLen; + } + length -= OPAQUE8_LEN + certReqCtxLen; + fragSz -= OPAQUE8_LEN + certReqCtxLen; /* Certificate list length. */ c32to24(listSz, output + i); i += CERT_HEADER_SZ; @@ -3978,6 +4019,14 @@ int SendTls13Certificate(WOLFSSL* ssl) ssl->options.serverState = SERVER_CERT_COMPLETE; } +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->certReqCtx != NULL) { + CertReqCtx* ctx = ssl->certReqCtx; + ssl->certReqCtx = ssl->certReqCtx->next; + XFREE(ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + return ret; } @@ -4344,7 +4393,23 @@ exit_scv: static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) { - return ProcessPeerCerts(ssl, input, inOutIdx, totalSz); + int ret; + + ret = ProcessPeerCerts(ssl, input, inOutIdx, totalSz); + if (ret != 0) + return ret; + +#if !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->options.handShakeState == HANDSHAKE_DONE) { + /* reset handshake states */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.acceptState = TICKET_SENT; + ssl->options.handShakeState = SERVER_FINISHED_COMPLETE; + } +#endif + + return 0; } #if !defined(NO_RSA) || defined(HAVE_ECC) @@ -4679,6 +4744,8 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, byte* secret; byte mac[MAX_DIGEST_SIZE]; + WOLFSSL_ENTER("DoTls13Finished"); + /* check against totalSz */ if (*inOutIdx + size + ssl->keys.padSz > totalSz) return BUFFER_E; @@ -4724,22 +4791,18 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Force input exhaustion at ProcessReply by consuming padSz. */ *inOutIdx += size + ssl->keys.padSz; - if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->options.side == WOLFSSL_SERVER_END && + !ssl->options.handShakeDone) { /* Setup keys for application data messages from client. */ if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; } -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_CLIENT_END) { - ssl->options.serverState = SERVER_FINISHED_COMPLETE; - if (!ssl->options.resuming) { - ssl->options.handShakeState = HANDSHAKE_DONE; - ssl->options.handShakeDone = 1; - } - } -#endif #ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) + ssl->options.serverState = SERVER_FINISHED_COMPLETE; +#endif +#ifndef NO_WOLFSSL_SERVER if (ssl->options.side == WOLFSSL_SERVER_END) { ssl->options.clientState = CLIENT_FINISHED_COMPLETE; ssl->options.handShakeState = HANDSHAKE_DONE; @@ -4747,6 +4810,8 @@ static int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif + WOLFSSL_LEAVE("DoTls13Finished", 0); + return 0; } #endif /* NO_CERTS */ @@ -4767,6 +4832,8 @@ int SendTls13Finished(WOLFSSL* ssl) int outputSz; byte* secret; + WOLFSSL_ENTER("SendTls13Finished"); + outputSz = MAX_DIGEST_SIZE + DTLS_HANDSHAKE_HEADER_SZ + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) @@ -4813,12 +4880,6 @@ int SendTls13Finished(WOLFSSL* ssl) AddSession(ssl); /* just try */ #endif } - else { - if (ssl->options.side == WOLFSSL_CLIENT_END) { - ssl->options.handShakeState = HANDSHAKE_DONE; - ssl->options.handShakeDone = 1; - } - } #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); @@ -4844,7 +4905,8 @@ int SendTls13Finished(WOLFSSL* ssl) return ret; } - if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (ssl->options.side == WOLFSSL_CLIENT_END && + !ssl->options.handShakeDone) { /* Setup keys for application data messages. */ if ((ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE)) != 0) return ret; @@ -4854,6 +4916,23 @@ int SendTls13Finished(WOLFSSL* ssl) #endif } + if (ssl->options.resuming) { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->options.resuming) { + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + } + } +#endif + + WOLFSSL_LEAVE("SendTls13Finished", ret); + return ret; } @@ -4872,6 +4951,8 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl) int outputSz; word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + WOLFSSL_ENTER("SendTls13KeyUpdate"); + outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) @@ -4920,6 +5001,8 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl) if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) return ret; + WOLFSSL_LEAVE("SendTls13KeyUpdate", ret); + return ret; } @@ -4938,6 +5021,8 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, int ret; word32 i = *inOutIdx; + WOLFSSL_ENTER("DoTls13KeyUpdate"); + /* check against totalSz */ if (OPAQUE8_LEN != totalSz) return BUFFER_E; @@ -4970,6 +5055,9 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->keys.keyUpdateRespond) return SendTls13KeyUpdate(ssl); + + WOLFSSL_LEAVE("DoTls13KeyUpdate", ret); + return 0; } @@ -5244,6 +5332,11 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT case certificate_request: + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (ssl->msgsReceived.got_finished) + ; + else + #endif if (ssl->msgsReceived.got_certificate_request) { WOLFSSL_MSG("Duplicate CertificateRequest received"); return DUPLICATE_MSG_E; @@ -5267,6 +5360,11 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) break; case finished: + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + if (1) { + } + else + #endif if (ssl->msgsReceived.got_finished) { WOLFSSL_MSG("Duplicate Finished received"); return DUPLICATE_MSG_E; @@ -5331,7 +5429,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (ssl->options.handShakeState == HANDSHAKE_DONE && type != session_ticket && type != certificate_request && - type != key_update) { + type != certificate && type != key_update) { WOLFSSL_MSG("HandShake message after handshake complete"); SendAlert(ssl, alert_fatal, unexpected_message); return OUT_OF_ORDER_E; @@ -5766,7 +5864,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) } #endif /* NO_HANDSHAKE_DONE_CB */ - WOLFSSL_LEAVE("SSL_connect()", SSL_SUCCESS); + WOLFSSL_LEAVE("wolfSSL_connect_TLSv13()", SSL_SUCCESS); return SSL_SUCCESS; default: @@ -5906,6 +6004,84 @@ int wolfSSL_update_keys(WOLFSSL* ssl) return ret; } +#if !defined(NO_CERTS) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* Allow post-handshake authentication in TLS v1.3 connections. + * + * ctx The SSL/TLS CTX object. + * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and + * 0 on success. + */ +int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + if (ctx->method->side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->postHandshakeAuth = 1; + + return 0; +} + +/* Allow post-handshake authentication in TLS v1.3 connection. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * SIDE_ERROR when not a server and 0 on success. + */ +int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl) +{ + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.postHandshakeAuth = 1; + + return 0; +} + +/* Request a certificate of the client. + * Can be called any time after handshake completion. + * A maximum of 256 requests can be sent on a connection. + * + * ssl SSL/TLS object. + */ +int wolfSSL_request_certificate(WOLFSSL* ssl) +{ + int ret; + CertReqCtx* certReqCtx; + + if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) + return BAD_FUNC_ARG; + if (ssl->options.side == WOLFSSL_CLIENT_END) + return SIDE_ERROR; + if (ssl->options.handShakeState != HANDSHAKE_DONE) + return NOT_READY_ERROR; + if (!ssl->options.postHandshakeAuth) + return POST_HAND_AUTH_ERROR; + + certReqCtx = XMALLOC(sizeof(CertReqCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certReqCtx == NULL) + return MEMORY_E; + XMEMSET(certReqCtx, 0, sizeof(CertReqCtx)); + certReqCtx->next = ssl->certReqCtx; + certReqCtx->len = 1; + if (certReqCtx->next != NULL) + certReqCtx->ctx = certReqCtx->next->ctx + 1; + ssl->certReqCtx = certReqCtx; + + ret = SendTls13CertificateRequest(ssl, &certReqCtx->ctx, certReqCtx->len); + if (ret == WANT_WRITE) + ret = SSL_ERROR_WANT_WRITE; + else if (ret == 0) + ret = SSL_SUCCESS; + return ret; +} +#endif /* !NO_CERTS && WOLFSSL_POST_HANDSHAKE_AUTH */ + /* The server accepting a connection from a client. * The protocol version is expecting to be TLS v1.3. * If the client downgrades, and older versions of the protocol are compiled @@ -6042,7 +6218,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl) #ifndef NO_CERTS if (!ssl->options.resuming) { if (ssl->options.verifyPeer) { - ssl->error = SendTls13CertificateRequest(ssl); + ssl->error = SendTls13CertificateRequest(ssl, NULL, 0); if (ssl->error != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index c81d38058..4e5ef76cb 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -253,8 +253,14 @@ void bench_rng(void); #if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND) && \ !defined(HAVE_STACK_SIZE) +#ifdef __cplusplus + extern "C" { +#endif WOLFSSL_API int wolfSSL_Debugging_ON(void); WOLFSSL_API void wolfSSL_Debugging_OFF(void); +#ifdef __cplusplus + } /* extern "C" */ +#endif #endif #if !defined(NO_RSA) || !defined(NO_DH) \ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 426ac14a8..26b885de5 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -307,7 +307,13 @@ int memcb_test(void); #if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND) && \ !defined(OPENSSL_EXTRA) && !defined(HAVE_STACK_SIZE) - int wolfSSL_Debugging_ON(void); +#ifdef __cplusplus + extern "C" { +#endif + WOLFSSL_API int wolfSSL_Debugging_ON(); +#ifdef __cplusplus + } /* extern "C" */ +#endif #endif /* General big buffer size for many tests. */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index c797c7f55..c6976ab87 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -164,10 +164,11 @@ enum wolfSSL_ErrorCodes { /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ - UNSUPPORTED_SUITE = -500, /* unsupported cipher suite */ - MATCH_SUITE_ERROR = -501, /* can't match cipher suite */ - COMPRESSION_ERROR = -502, /* compression mismatch */ - KEY_SHARE_ERROR = -503 /* key share mismatch */ + UNSUPPORTED_SUITE = -500, /* unsupported cipher suite */ + MATCH_SUITE_ERROR = -501, /* can't match cipher suite */ + COMPRESSION_ERROR = -502, /* compression mismatch */ + KEY_SHARE_ERROR = -503, /* key share mismatch */ + POST_HAND_AUTH_ERROR = -504 /* client won't do post-hand auth */ /* end negotiation parameter errors only 10 for now */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 42d6376ab..c35b7b2e7 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1121,6 +1121,7 @@ enum Misc { MAX_PSK_KEY_LEN = 64, /* max psk key supported */ MIN_PSK_ID_LEN = 6, /* min length of identities */ MIN_PSK_BINDERS_LEN= 33, /* min length of binders */ + MAX_TICKET_AGE_SECS= 10, /* maximum ticket age in seconds */ MAX_WOLFSSL_FILE_SIZE = 1024 * 1024 * 4, /* 4 mb file size alloc limit */ @@ -1787,6 +1788,9 @@ typedef enum { #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d, #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + TLSX_POST_HANDSHAKE_AUTH = 0x0031, + #endif #endif TLSX_RENEGOTIATION_INFO = 0xff01 } TLSX_Type; @@ -2179,6 +2183,9 @@ struct WOLFSSL_CTX { byte noTicketTls13; /* Server won't create new Ticket */ byte noPskDheKe; /* Don't use (EC)DHE with PSK */ #endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + byte postHandshakeAuth;/* Post-handshake authentication supported. */ +#endif #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) byte dtlsSctp; /* DTLS-over-SCTP mode */ word16 dtlsMtuSz; /* DTLS MTU size */ @@ -2771,6 +2778,10 @@ typedef struct Options { #endif word16 keepResources:1; /* Keep resources after handshake */ word16 useClientOrder:1; /* Use client's cipher order */ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + word16 postHandshakeAuth:1;/* Client send post_handshake_auth + * extendion. */ +#endif /* need full byte values for this section */ byte processReply; /* nonblocking resume */ @@ -3069,6 +3080,15 @@ typedef struct HS_Hashes { WOLFSSL_LOCAL int NotifyWriteSide(WOLFSSL* ssl, int err); #endif /* HAVE_WRITE_DUP */ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) +typedef struct CertReqCtx CertReqCtx; + +struct CertReqCtx { + CertReqCtx* next; + byte len; + byte ctx; +}; +#endif /* wolfSSL ssl type */ struct WOLFSSL { @@ -3208,8 +3228,8 @@ struct WOLFSSL { CallbackFuzzer fuzzerCb; /* for testing with using fuzzer */ void* fuzzerCtx; /* user defined pointer */ #endif -#ifdef WOLFSSL_TLS13 - buffer clientCertCtx; /* Certificate context in request */ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + CertReqCtx* certReqCtx; #endif #ifdef KEEP_PEER_CERT WOLFSSL_X509 peerCert; /* X509 peer cert */ @@ -3452,7 +3472,8 @@ WOLFSSL_LOCAL int SendTls13Certificate(WOLFSSL*); #endif WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*); #ifdef WOLFSSL_TLS13 -WOLFSSL_LOCAL int SendTls13CertificateRequest(WOLFSSL*); +WOLFSSL_LOCAL int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, + int reqCtxLen); #endif WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*); WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 59608670b..1a8c0c648 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -412,6 +412,9 @@ WOLFSSL_API int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_no_dhe_psk(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_update_keys(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx); +WOLFSSL_API int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_request_certificate(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_accept_TLSv13(WOLFSSL*); #endif WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX*);