diff --git a/src/dtls13.c b/src/dtls13.c index 974469b0f..6430600f5 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -1209,6 +1209,11 @@ int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output, return 0; } +int Dtls13MinimumRecordLength(WOLFSSL* ssl) +{ + return Dtls13GetRlHeaderLength(ssl, 1) + DTLS13_MIN_CIPHERTEXT; +} + /** * Dtls13EncryptRecordNumber() - encrypt record number in the header * @ssl: ssl object @@ -1225,9 +1230,15 @@ int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength) if (ssl == NULL || hdr == NULL) return BAD_FUNC_ARG; +#ifdef HAVE_NULL_CIPHER + /* Do not encrypt record numbers with null cipher. See RFC 9150 Sec 9 */ + if (ssl->specs.bulk_cipher_algorithm == wolfssl_cipher_null) + return 0; +#endif /*HAVE_NULL_CIPHER */ + /* we need at least a 16 bytes of ciphertext to encrypt record number see 4.2.3*/ - if (recordLength < Dtls13GetRlHeaderLength(ssl, 1) + DTLS13_MIN_CIPHERTEXT) + if (recordLength < Dtls13MinimumRecordLength(ssl)) return BUFFER_ERROR; seqLength = (*hdr & DTLS13_LEN_BIT) ? DTLS13_SEQ_16_LEN : DTLS13_SEQ_8_LEN; @@ -1453,17 +1464,22 @@ int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input, hdrInfo->recordLength = inputSize - idx; } - /* minimum size for a dtls1.3 packet is 16 bytes (to have enough ciphertext - to create record number xor mask). (draft 43 - Sec 4.2.3) */ - if (hdrInfo->recordLength < DTLS13_RN_MASK_SIZE) - return LENGTH_ERROR; - if (inputSize < idx + DTLS13_RN_MASK_SIZE) - return BUFFER_ERROR; + /* Do not encrypt record numbers with null cipher. See RFC 9150 Sec 9 */ + if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) + { + /* minimum size for a dtls1.3 packet is 16 bytes (to have enough + * ciphertext to create record number xor mask). + * (draft 43 - Sec 4.2.3) */ + if (hdrInfo->recordLength < DTLS13_RN_MASK_SIZE) + return LENGTH_ERROR; + if (inputSize < idx + DTLS13_RN_MASK_SIZE) + return BUFFER_ERROR; - ret = Dtls13EncryptDecryptRecordNumber(ssl, seqNum, seqLen, input + idx, - DEPROTECT); - if (ret != 0) - return ret; + ret = Dtls13EncryptDecryptRecordNumber(ssl, seqNum, seqLen, input + idx, + DEPROTECT); + if (ret != 0) + return ret; + } if (seqLen == DTLS13_SEQ_16_LEN) { hdrInfo->seqHiPresent = 1; diff --git a/src/internal.c b/src/internal.c index 747dc621a..2fc63753f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -11255,6 +11255,11 @@ static int GetDtls13RecordHeader(WOLFSSL* ssl, word32* inOutIdx, if (ret != 0) return ret; + if (ssl->dtls13CurRlLength > sizeof(ssl->dtls13CurRL)) { + WOLFSSL_MSG("Record header too long"); + return SEQUENCE_ERROR; + } + if (readSize < ssl->dtls13CurRlLength + DTLS13_RN_MASK_SIZE) { /* when using DTLS over a medium that does not guarantee that a full * message is received in a single read, we may end up without the full @@ -24789,6 +24794,14 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) if (IsEncryptionOn(ssl, 1) || ssl->options.tls1_3) outputSz += cipherExtraData(ssl); +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (ssl->options.dtls) { + unsigned int cidSz = 0; + if (wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) + outputSz += cidSz; + } +#endif + /* check for available size */ if ((ret = CheckAvailableSize(ssl, outputSz)) != 0) return ssl->error = ret; @@ -25935,7 +25948,7 @@ void SetErrorString(int error, char* str) */ #ifndef NO_ERROR_STRINGS - #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \ + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_QT) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) #define SUITE_INFO(x,y,z,w,v,u) {(x),(y),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE} #define SUITE_ALIAS(x,z,w,v,u) {(x),"",(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS}, @@ -25944,7 +25957,7 @@ void SetErrorString(int error, char* str) #define SUITE_ALIAS(x,z,w,v,u) {(x),"",(z),(w),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS}, #endif #else - #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \ + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_QT) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) #define SUITE_INFO(x,y,z,w,v,u) {(x),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NONE} #define SUITE_ALIAS(x,z,w,v,u) {(x),(z),(w),(v),(u),WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS}, @@ -26806,13 +26819,16 @@ const char* wolfSSL_get_cipher_name_iana(WOLFSSL* ssl) } int GetCipherSuiteFromName(const char* name, byte* cipherSuite0, - byte* cipherSuite, int* flags) + byte* cipherSuite, byte* major, byte* minor, int* flags) { int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); int i; unsigned long len; const char* nameDelim; + (void)major; + (void)minor; + /* Support trailing : */ nameDelim = XSTRSTR(name, ":"); if (nameDelim) @@ -26830,9 +26846,19 @@ int GetCipherSuiteFromName(const char* name, byte* cipherSuite0, #endif if (found) { - *cipherSuite0 = cipher_names[i].cipherSuite0; - *cipherSuite = cipher_names[i].cipherSuite; - *flags = cipher_names[i].flags; + if (cipherSuite0 != NULL) + *cipherSuite0 = cipher_names[i].cipherSuite0; + if (cipherSuite != NULL) + *cipherSuite = cipher_names[i].cipherSuite; +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_QT) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) + if (major != NULL) + *major = cipher_names[i].major; + if (minor != NULL) + *minor = cipher_names[i].minor; +#endif + if (flags != NULL) + *flags = cipher_names[i].flags; ret = 0; break; } diff --git a/src/ssl.c b/src/ssl.c index ccb32cc16..0e69de94f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8412,6 +8412,8 @@ static int CheckcipherList(const char* list) char name[MAX_SUITE_NAME + 1]; word32 length = MAX_SUITE_NAME; word32 current_length; + byte major = INVALID_BYTE; + byte minor = INVALID_BYTE; next = XSTRSTR(next, ":"); @@ -8436,10 +8438,10 @@ static int CheckcipherList(const char* list) break; } - ret = wolfSSL_get_cipher_suite_from_name(name, &cipherSuite0, - &cipherSuite1, &flags); + ret = GetCipherSuiteFromName(name, &cipherSuite0, + &cipherSuite1, &major, &minor, &flags); if (ret == 0) { - if (cipherSuite0 == TLS13_BYTE) { + if (cipherSuite0 == TLS13_BYTE || minor == TLSv1_3_MINOR) { /* TLSv13 suite */ findTLSv13Suites = 1; } @@ -14297,7 +14299,8 @@ int wolfSSL_get_cipher_suite_from_name(const char* name, byte* cipherSuite0, (cipherSuite == NULL) || (flags == NULL)) return BAD_FUNC_ARG; - return GetCipherSuiteFromName(name, cipherSuite0, cipherSuite, flags); + return GetCipherSuiteFromName(name, cipherSuite0, cipherSuite, NULL, NULL, + flags); } diff --git a/src/tls.c b/src/tls.c index 94742c9fb..0aff79169 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13500,7 +13500,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) ssl->arrays->client_identity, MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName); if (GetCipherSuiteFromName(cipherName, &cipherSuite0, - &cipherSuite, &cipherSuiteFlags) != 0) { + &cipherSuite, NULL, NULL, &cipherSuiteFlags) != 0) { return PSK_KEY_ERROR; } } diff --git a/src/tls13.c b/src/tls13.c index cfc674ef0..0d35d9bc4 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3199,6 +3199,7 @@ typedef struct BuildMsg13Args { word32 idx; word32 headerSz; word16 size; + word32 paddingSz; } BuildMsg13Args; static void FreeBuildMsg13Args(WOLFSSL* ssl, void* pArgs) @@ -3304,7 +3305,14 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, args->sz++; /* Authentication data at the end. */ args->sz += ssl->specs.aead_mac_size; - +#ifdef WOLFSSL_DTLS13 + /* Pad to minimum length */ + if (ssl->options.dtls && + args->sz < (word32)Dtls13MinimumRecordLength(ssl)) { + args->paddingSz = Dtls13MinimumRecordLength(ssl) - args->sz; + args->sz = Dtls13MinimumRecordLength(ssl); + } +#endif if (sizeOnly) return (int)args->sz; @@ -3348,6 +3356,9 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, /* The real record content type goes at the end of the data. */ output[args->idx++] = (byte)type; + /* Double check that any necessary padding is zero'd out */ + XMEMSET(output + args->idx, 0, args->paddingSz); + args->idx += args->paddingSz; ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; } @@ -3393,7 +3404,8 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #ifdef WOLFSSL_DTLS13 if (ret == 0 && ssl->options.dtls) { /* AAD points to the header. Reuse the variable */ - ret = Dtls13EncryptRecordNumber(ssl, (byte*)aad, (word16)args->sz); + ret = Dtls13EncryptRecordNumber(ssl, (byte*)aad, + (word16)args->sz); } #endif /* WOLFSSL_DTLS13 */ } @@ -3940,7 +3952,7 @@ static int SetupPskKey(WOLFSSL* ssl, PreSharedKey* psk, int clientHello) MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName); if (GetCipherSuiteFromName(cipherName, &cipherSuite0, - &cipherSuite, &cipherSuiteFlags) != 0) { + &cipherSuite, NULL, NULL, &cipherSuiteFlags) != 0) { WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR); return PSK_KEY_ERROR; } @@ -5852,7 +5864,7 @@ int FindPskSuite(const WOLFSSL* ssl, PreSharedKey* psk, byte* psk_key, if (*psk_keySz != 0) { int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE; *found = (GetCipherSuiteFromName(cipherName, &cipherSuite0, - &cipherSuite, &cipherSuiteFlags) == 0); + &cipherSuite, NULL, NULL, &cipherSuiteFlags) == 0); (void)cipherSuiteFlags; } } diff --git a/tests/api.c b/tests/api.c index 7ade479cb..f637aa943 100644 --- a/tests/api.c +++ b/tests/api.c @@ -599,6 +599,248 @@ static int testDevId = WOLFSSL_CAAM_DEVID; static int testDevId = INVALID_DEVID; #endif +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_RSA) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) + +/* This set of memio functions allows for more fine tuned control of the TLS + * connection operations. For new tests, try to use ssl_memio first. */ + +/* To dump the memory in gdb use + * dump memory client.bin test_ctx.c_buff test_ctx.c_buff+test_ctx.c_len + * dump memory server.bin test_ctx.s_buff test_ctx.s_buff+test_ctx.s_len + * This can be imported into Wireshark by transforming the file with + * od -Ax -tx1 -v client.bin > client.bin.hex + * od -Ax -tx1 -v server.bin > server.bin.hex + * And then loading test_output.dump.hex into Wireshark using the + * "Import from Hex Dump..." option ion and selecting the TCP + * encapsulation option. + */ + +#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES + +static WC_INLINE int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz, + void *ctx) +{ + struct test_memio_ctx *test_ctx; + byte *buf; + int *len; + + test_ctx = (struct test_memio_ctx*)ctx; + + if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { + buf = test_ctx->c_buff; + len = &test_ctx->c_len; + } + else { + buf = test_ctx->s_buff; + len = &test_ctx->s_len; + } + + if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + +#ifdef WOLFSSL_DUMP_MEMIO_STREAM + { + char dump_file_name[64]; + WOLFSSL_BIO *dump_file; + sprintf(dump_file_name, "%s/%s.dump", tmpDirName, currentTestName); + dump_file = wolfSSL_BIO_new_file(dump_file_name, "a"); + if (dump_file != NULL) { + (void)wolfSSL_BIO_write(dump_file, data, sz); + wolfSSL_BIO_free(dump_file); + } + } +#endif + XMEMCPY(buf + *len, data, (size_t)sz); + *len += sz; + + return sz; +} + +static WC_INLINE int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, + void *ctx) +{ + struct test_memio_ctx *test_ctx; + int read_sz; + byte *buf; + int *len; + + test_ctx = (struct test_memio_ctx*)ctx; + + if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { + buf = test_ctx->s_buff; + len = &test_ctx->s_len; + } + else { + buf = test_ctx->c_buff; + len = &test_ctx->c_len; + } + + if (*len == 0) + return WOLFSSL_CBIO_ERR_WANT_READ; + + read_sz = sz < *len ? sz : *len; + + XMEMCPY(data, buf, (size_t)read_sz); + XMEMMOVE(buf, buf + read_sz,(size_t) (*len - read_sz)); + + *len -= read_sz; + + return read_sz; +} + +int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, + int max_rounds, int *rounds) +{ + byte handshake_complete = 0, hs_c = 0, hs_s = 0; + int ret, err; + + if (rounds != NULL) + *rounds = 0; + while (!handshake_complete && max_rounds > 0) { + if (!hs_c) { + wolfSSL_SetLoggingPrefix("client"); + ret = wolfSSL_connect(ssl_c); + wolfSSL_SetLoggingPrefix(NULL); + if (ret == WOLFSSL_SUCCESS) { + hs_c = 1; + } + else { + err = wolfSSL_get_error(ssl_c, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + if (!hs_s) { + wolfSSL_SetLoggingPrefix("server"); + ret = wolfSSL_accept(ssl_s); + wolfSSL_SetLoggingPrefix(NULL); + if (ret == WOLFSSL_SUCCESS) { + hs_s = 1; + } + else { + err = wolfSSL_get_error(ssl_s, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + handshake_complete = hs_c && hs_s; + max_rounds--; + if (rounds != NULL) + *rounds = *rounds + 1; + } + + if (!handshake_complete) + return -1; + + return 0; +} + +int test_memio_setup_ex(struct test_memio_ctx *ctx, + WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, + method_provider method_c, method_provider method_s, + byte *caCert, int caCertSz, byte *serverCert, int serverCertSz, + byte *serverKey, int serverKeySz) +{ + int ret; + (void)caCert; + (void)caCertSz; + (void)serverCert; + (void)serverCertSz; + (void)serverKey; + (void)serverKeySz; + + if (ctx_c != NULL && *ctx_c == NULL) { + *ctx_c = wolfSSL_CTX_new(method_c()); + if (*ctx_c == NULL) + return -1; +#ifndef NO_CERTS + if (caCert == NULL) { + ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0); + } + else { + ret = wolfSSL_CTX_load_verify_buffer(*ctx_c, caCert, (long)caCertSz, + WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) + return -1; +#endif /* NO_CERTS */ + wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb); + wolfSSL_SetIOSend(*ctx_c, test_memio_write_cb); + if (ctx->c_ciphers != NULL) { + ret = wolfSSL_CTX_set_cipher_list(*ctx_c, ctx->c_ciphers); + if (ret != WOLFSSL_SUCCESS) + return -1; + } + } + + if (ctx_s != NULL && *ctx_s == NULL) { + *ctx_s = wolfSSL_CTX_new(method_s()); + if (*ctx_s == NULL) + return -1; +#ifndef NO_CERTS + if (serverKey == NULL) { + ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_s, svrKeyFile, + WOLFSSL_FILETYPE_PEM); + } + else { + ret = wolfSSL_CTX_use_PrivateKey_buffer(*ctx_s, serverKey, + (long)serverKeySz, WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) + return- -1; + + if (serverCert == NULL) { + ret = wolfSSL_CTX_use_certificate_file(*ctx_s, svrCertFile, + WOLFSSL_FILETYPE_PEM); + } + else { + ret = wolfSSL_CTX_use_certificate_chain_buffer_format(*ctx_s, + serverCert, (long)serverCertSz, WOLFSSL_FILETYPE_ASN1); + } + if (ret != WOLFSSL_SUCCESS) + return -1; +#endif /* NO_CERTS */ + wolfSSL_SetIORecv(*ctx_s, test_memio_read_cb); + wolfSSL_SetIOSend(*ctx_s, test_memio_write_cb); + if (ctx->s_ciphers != NULL) { + ret = wolfSSL_CTX_set_cipher_list(*ctx_s, ctx->s_ciphers); + if (ret != WOLFSSL_SUCCESS) + return -1; + } + } + + if (ctx_c != NULL && ssl_c != NULL) { + *ssl_c = wolfSSL_new(*ctx_c); + if (*ssl_c == NULL) + return -1; + wolfSSL_SetIOWriteCtx(*ssl_c, ctx); + wolfSSL_SetIOReadCtx(*ssl_c, ctx); + } + if (ctx_s != NULL && ssl_s != NULL) { + *ssl_s = wolfSSL_new(*ctx_s); + if (*ssl_s == NULL) + return -1; + wolfSSL_SetIOWriteCtx(*ssl_s, ctx); + wolfSSL_SetIOReadCtx(*ssl_s, ctx); +#if !defined(NO_DH) + SetDH(*ssl_s); +#endif + } + + return 0; +} + +int test_memio_setup(struct test_memio_ctx *ctx, + WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, + method_provider method_c, method_provider method_s) +{ + return test_memio_setup_ex(ctx, ctx_c, ctx_s, ssl_c, ssl_s, method_c, + method_s, NULL, 0, NULL, 0, NULL, 0); +} +#endif /*----------------------------------------------------------------------------* | BIO with fixed read/write size @@ -93839,6 +94081,144 @@ static int test_dtls_old_seq_number(void) return EXPECT_RESULT(); } +static int test_dtls13_basic_connection_id(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(WOLFSSL_DTLS_CID) + unsigned char client_cid[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + unsigned char readBuf[30]; + const char* params[] = { +#ifndef NO_SHA256 +#ifdef WOLFSSL_AES_128 +#ifdef HAVE_AESGCM + "TLS13-AES128-GCM-SHA256", +#endif +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + "TLS13-CHACHA20-POLY1305-SHA256", +#endif +#ifdef HAVE_AESCCM + "TLS13-AES128-CCM-8-SHA256", + "TLS13-AES128-CCM-SHA256", +#endif +#endif +#ifdef HAVE_NULL_CIPHER + "TLS13-SHA256-SHA256", +#endif +#endif + }; + size_t i; + + /* We check if the side included the CID in their output */ +#define CLIENT_CID() XMEMMEM(test_ctx.s_buff, test_ctx.s_len, \ + client_cid, sizeof(client_cid)) +#define SERVER_CID() XMEMMEM(test_ctx.c_buff, test_ctx.c_len, \ + server_cid, sizeof(server_cid)) + + printf("\n"); + for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) { + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + printf("Testing %s ... ", params[i]); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i]), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i]), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, server_cid, sizeof(server_cid)), + 1); + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, client_cid, sizeof(client_cid)), + 1); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(SERVER_CID()); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(SERVER_CID()); + /* Client second flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + /* Server process flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + /* Client process flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + + /* Write some data */ + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], XSTRLEN(params[i])), + XSTRLEN(params[i])); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], XSTRLEN(params[i])), + XSTRLEN(params[i])); + ExpectNotNull(SERVER_CID()); + /* Read the data */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + /* Write short data */ + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], 1), 1); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], 1), 1); + ExpectNotNull(SERVER_CID()); + /* Read the short data */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + + /* Close connection */ + ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(SERVER_CID()); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); + + if (EXPECT_SUCCESS()) + printf("ok\n"); + else + printf("failed\n"); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + } + +#undef CLIENT_CID +#undef SERVER_CID + +#endif + return EXPECT_RESULT(); +} + #if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ defined(HAVE_LIBOQS) static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx) @@ -96240,6 +96620,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_dtls13_frag_ch_pq), TEST_DECL(test_dtls_empty_keyshare_with_cookie), TEST_DECL(test_dtls_old_seq_number), + TEST_DECL(test_dtls13_basic_connection_id), TEST_DECL(test_tls13_pq_groups), TEST_DECL(test_tls13_early_data), TEST_DECL(test_tls_multi_handshakes_one_record), diff --git a/tests/utils.h b/tests/utils.h index ecc634e6c..8747ce4e5 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -124,25 +124,6 @@ int link_file(const char* in, const char* out) #endif #endif /* !NO_FILESYSTEM */ -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_RSA) && \ - !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) - -/* This set of memio functions allows for more fine tuned control of the TLS - * connection operations. For new tests, try to use ssl_memio first. */ - -/* To dump the memory in gdb use - * dump memory client.bin test_ctx.c_buff test_ctx.c_buff+test_ctx.c_len - * dump memory server.bin test_ctx.s_buff test_ctx.s_buff+test_ctx.s_len - * This can be imported into Wireshark by transforming the file with - * od -Ax -tx1 -v client.bin > client.bin.hex - * od -Ax -tx1 -v server.bin > server.bin.hex - * And then loading test_output.dump.hex into Wireshark using the - * "Import from Hex Dump..." option ion and selecting the TCP - * encapsulation option. - */ - -#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES - #define TEST_MEMIO_BUF_SZ (64 * 1024) struct test_memio_ctx { @@ -153,7 +134,6 @@ struct test_memio_ctx int s_len; const char* s_ciphers; }; - int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, int max_rounds, int *rounds); int test_memio_setup(struct test_memio_ctx *ctx, @@ -165,228 +145,6 @@ int test_memio_setup_ex(struct test_memio_ctx *ctx, byte *caCert, int caCertSz, byte *serverCert, int serverCertSz, byte *serverKey, int serverKeySz); - -static WC_INLINE int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz, - void *ctx) -{ - struct test_memio_ctx *test_ctx; - byte *buf; - int *len; - - test_ctx = (struct test_memio_ctx*)ctx; - - if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { - buf = test_ctx->c_buff; - len = &test_ctx->c_len; - } - else { - buf = test_ctx->s_buff; - len = &test_ctx->s_len; - } - - if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ) - return WOLFSSL_CBIO_ERR_WANT_WRITE; - -#ifdef WOLFSSL_DUMP_MEMIO_STREAM - { - WOLFSSL_BIO *dump_file = wolfSSL_BIO_new_file("test_memio.dump", "a"); - if (dump_file != NULL) { - (void)wolfSSL_BIO_write(dump_file, data, sz); - wolfSSL_BIO_free(dump_file); - } - } -#endif - XMEMCPY(buf + *len, data, (size_t)sz); - *len += sz; - - return sz; -} - -static WC_INLINE int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, - void *ctx) -{ - struct test_memio_ctx *test_ctx; - int read_sz; - byte *buf; - int *len; - - test_ctx = (struct test_memio_ctx*)ctx; - - if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { - buf = test_ctx->s_buff; - len = &test_ctx->s_len; - } - else { - buf = test_ctx->c_buff; - len = &test_ctx->c_len; - } - - if (*len == 0) - return WOLFSSL_CBIO_ERR_WANT_READ; - - read_sz = sz < *len ? sz : *len; - - XMEMCPY(data, buf, (size_t)read_sz); - XMEMMOVE(buf, buf + read_sz,(size_t) (*len - read_sz)); - - *len -= read_sz; - - return read_sz; -} - -int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, - int max_rounds, int *rounds) -{ - byte handshake_complete = 0, hs_c = 0, hs_s = 0; - int ret, err; - - if (rounds != NULL) - *rounds = 0; - while (!handshake_complete && max_rounds > 0) { - if (!hs_c) { - wolfSSL_SetLoggingPrefix("client"); - ret = wolfSSL_connect(ssl_c); - wolfSSL_SetLoggingPrefix(NULL); - if (ret == WOLFSSL_SUCCESS) { - hs_c = 1; - } - else { - err = wolfSSL_get_error(ssl_c, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) - return -1; - } - } - if (!hs_s) { - wolfSSL_SetLoggingPrefix("server"); - ret = wolfSSL_accept(ssl_s); - wolfSSL_SetLoggingPrefix(NULL); - if (ret == WOLFSSL_SUCCESS) { - hs_s = 1; - } - else { - err = wolfSSL_get_error(ssl_s, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) - return -1; - } - } - handshake_complete = hs_c && hs_s; - max_rounds--; - if (rounds != NULL) - *rounds = *rounds + 1; - } - - if (!handshake_complete) - return -1; - - return 0; -} - -int test_memio_setup_ex(struct test_memio_ctx *ctx, - WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, - method_provider method_c, method_provider method_s, - byte *caCert, int caCertSz, byte *serverCert, int serverCertSz, - byte *serverKey, int serverKeySz) -{ - int ret; - (void)caCert; - (void)caCertSz; - (void)serverCert; - (void)serverCertSz; - (void)serverKey; - (void)serverKeySz; - - if (ctx_c != NULL && *ctx_c == NULL) { - *ctx_c = wolfSSL_CTX_new(method_c()); - if (*ctx_c == NULL) - return -1; -#ifndef NO_CERTS - if (caCert == NULL) { - ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0); - } - else { - ret = wolfSSL_CTX_load_verify_buffer(*ctx_c, caCert, (long)caCertSz, - WOLFSSL_FILETYPE_ASN1); - } - if (ret != WOLFSSL_SUCCESS) - return -1; -#endif /* NO_CERTS */ - wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb); - wolfSSL_SetIOSend(*ctx_c, test_memio_write_cb); - if (ctx->c_ciphers != NULL) { - ret = wolfSSL_CTX_set_cipher_list(*ctx_c, ctx->c_ciphers); - if (ret != WOLFSSL_SUCCESS) - return -1; - } - } - - if (ctx_s != NULL && *ctx_s == NULL) { - *ctx_s = wolfSSL_CTX_new(method_s()); - if (*ctx_s == NULL) - return -1; -#ifndef NO_CERTS - if (serverKey == NULL) { - ret = wolfSSL_CTX_use_PrivateKey_file(*ctx_s, svrKeyFile, - WOLFSSL_FILETYPE_PEM); - } - else { - ret = wolfSSL_CTX_use_PrivateKey_buffer(*ctx_s, serverKey, - (long)serverKeySz, WOLFSSL_FILETYPE_ASN1); - } - if (ret != WOLFSSL_SUCCESS) - return- -1; - - if (serverCert == NULL) { - ret = wolfSSL_CTX_use_certificate_file(*ctx_s, svrCertFile, - WOLFSSL_FILETYPE_PEM); - } - else { - ret = wolfSSL_CTX_use_certificate_chain_buffer_format(*ctx_s, - serverCert, (long)serverCertSz, WOLFSSL_FILETYPE_ASN1); - } - if (ret != WOLFSSL_SUCCESS) - return -1; -#endif /* NO_CERTS */ - wolfSSL_SetIORecv(*ctx_s, test_memio_read_cb); - wolfSSL_SetIOSend(*ctx_s, test_memio_write_cb); - if (ctx->s_ciphers != NULL) { - ret = wolfSSL_CTX_set_cipher_list(*ctx_s, ctx->s_ciphers); - if (ret != WOLFSSL_SUCCESS) - return -1; - } - } - - if (ctx_c != NULL && ssl_c != NULL) { - *ssl_c = wolfSSL_new(*ctx_c); - if (*ssl_c == NULL) - return -1; - wolfSSL_SetIOWriteCtx(*ssl_c, ctx); - wolfSSL_SetIOReadCtx(*ssl_c, ctx); - } - if (ctx_s != NULL && ssl_s != NULL) { - *ssl_s = wolfSSL_new(*ctx_s); - if (*ssl_s == NULL) - return -1; - wolfSSL_SetIOWriteCtx(*ssl_s, ctx); - wolfSSL_SetIOReadCtx(*ssl_s, ctx); -#if !defined(NO_DH) - SetDH(*ssl_s); -#endif - } - - return 0; -} - -int test_memio_setup(struct test_memio_ctx *ctx, - WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, - method_provider method_c, method_provider method_s) -{ - return test_memio_setup_ex(ctx, ctx_c, ctx_s, ssl_c, ssl_s, method_c, - method_s, NULL, 0, NULL, 0, NULL, 0); -} -#endif - #if !defined(SINGLE_THREADED) && defined(WOLFSSL_COND) void signal_ready(tcp_ready* ready) { diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index fd901f988..31773a2df 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -3397,6 +3397,26 @@ char* mystrnstr(const char* s1, const char* s2, unsigned int n) } #endif +void *mymemmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + size_t i, j; + const char* h = (const char*)haystack; + const char* n = (const char*)needle; + if (needlelen > haystacklen) + return NULL; + for (i = 0; i <= haystacklen - needlelen; i++) { + for (j = 0; j < needlelen; j++) { + if (h[i + j] != n[j]) + break; + } + if (j == needlelen) + return (void*)(h + i); + } + return NULL; +} + + /* custom memory wrappers */ #ifdef WOLFSSL_NUCLEUS_1_2 diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d5d798672..dae335b2d 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1433,7 +1433,7 @@ enum { /* DTLSv1.3 parsing code copies the record header in a static buffer to decrypt * the record. Increasing the CID max size does increase also this buffer, * impacting on per-session runtime memory footprint. */ -#define DTLS_CID_MAX_SIZE 2 +#define DTLS_CID_MAX_SIZE 10 #endif #else #undef DTLS_CID_MAX_SIZE @@ -6647,7 +6647,7 @@ typedef struct CipherSuiteInfo { #endif byte cipherSuite0; byte cipherSuite; -#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \ +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_QT) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) byte minor; byte major; @@ -6677,7 +6677,7 @@ WOLFSSL_LOCAL const char* GetCipherNameIana(byte cipherSuite0, byte cipherSuite) WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_internal(WOLFSSL* ssl); WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_iana(WOLFSSL* ssl); WOLFSSL_LOCAL int GetCipherSuiteFromName(const char* name, byte* cipherSuite0, - byte* cipherSuite, int* flags); + byte* cipherSuite, byte* major, byte* minor, int* flags); enum encrypt_side { @@ -6828,6 +6828,7 @@ WOLFSSL_LOCAL int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out, word16 length); WOLFSSL_LOCAL int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out, enum ContentType content_type, word16 length); +WOLFSSL_LOCAL int Dtls13MinimumRecordLength(WOLFSSL* ssl); WOLFSSL_LOCAL int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength); WOLFSSL_LOCAL int Dtls13IsUnifiedHeader(byte header_flags); diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 6784ee6a2..e7edbc5b3 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -730,6 +730,7 @@ typedef struct w64wrapper { #define XMEMSET(b,c,l) memset((b),(c),(l)) #define XMEMCMP(s1,s2,n) memcmp((s1),(s2),(n)) #define XMEMMOVE(d,s,l) memmove((d),(s),(l)) + #define XMEMMEM(h,hl,n,nl) mymemmem((h),(hl),(n),(nl)) #define XSTRLEN(s1) strlen((s1)) #define XSTRNCPY(s1,s2,n) strncpy((s1),(s2),(n)) diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index ceb408d7a..cb36bfe7d 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1214,6 +1214,8 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #ifndef WOLFSSL_LEANPSK char* mystrnstr(const char* s1, const char* s2, unsigned int n); #endif + WOLFSSL_API void *mymemmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); #ifndef FILE_BUFFER_SIZE /* default static file buffer size for input, will use dynamic buffer if