Package: release.debian.org Severity: normal Tags: trixie User: [email protected] Usertags: pu
The attached debdiff for libcoap3 fixes CVE-2025-59391, CVE-2025-65493, CVE-2025-65494, CVE-2025-65495, CVE-2025-65496, CVE-2025-65497, CVE-2025-65498, CVE-2025-65499, CVE-2025-65500 and CVE-2025-65501 in Trixie. All CVEs are marked as no-dsa from the security team.
The same patch has been uploaded more than a week ago to unstable and nobody complained yet.
Thorsten
diff -Nru libcoap3-4.3.4/debian/changelog libcoap3-4.3.4/debian/changelog --- libcoap3-4.3.4/debian/changelog 2025-08-27 08:03:02.000000000 +0200 +++ libcoap3-4.3.4/debian/changelog 2025-12-29 18:23:22.000000000 +0100 @@ -1,3 +1,28 @@ +libcoap3 (4.3.4-1.1+deb13u2) trixie; urgency=medium + + * CVE-2025-59391 (Closes: #1122290) + fix OSCORE configuration file parsing issue + * CVE-2025-65493 (Closes: 1121415) + fix NULL pointer dereference + * CVE-2025-65494 + fix NULL pointer dereference + * CVE-2025-65495 + fix integer signedness + * CVE-2025-65496 + fix NULL pointer dereference + * CVE-2025-65497 + fix NULL pointer dereference + * CVE-2025-65498 + fix NULL pointer dereference + * CVE-2025-65499 + fix array index error + * CVE-2025-65500 + fix NULL pointer dereference + * CVE-2025-65501 + fix NULL pointer dereference + + -- Thorsten Alteholz <[email protected]> Mon, 29 Dec 2025 18:23:22 +0100 + libcoap3 (4.3.4-1.1+deb13u1) trixie; urgency=medium * Non-maintainer upload by the LTS Team. diff -Nru libcoap3-4.3.4/debian/patches/CVE-2025-59391.patch libcoap3-4.3.4/debian/patches/CVE-2025-59391.patch --- libcoap3-4.3.4/debian/patches/CVE-2025-59391.patch 1970-01-01 01:00:00.000000000 +0100 +++ libcoap3-4.3.4/debian/patches/CVE-2025-59391.patch 2025-12-21 11:31:12.000000000 +0100 @@ -0,0 +1,83 @@ +From d56fb48bffd625f779eaf4616ccda62e1a7f6fd3 Mon Sep 17 00:00:00 2001 +From: Jon Shallow <[email protected]> +Date: Thu, 4 Sep 2025 13:26:06 +0100 +Subject: [PATCH] OSCORE: Fix OSCORE configuration file parsing issue + +With a large boolean parameter value, (longer than "false"), memory +would be read past the "true" or "false" string boundaries in the ".rodata" +section when doing a memcmp(), potetially causing the application to crash +when calling coap_new_oscore_conf() with a specially crafted configuration +file. + +It also can provide a mechanism to determine the byte values following the +"true" or "false" string boundaries which could lead to accessing sensitive +information. The standard libcoap library does not have defined keys or +certificates. This can only be done by a specially crafted local application. + +Discovered by SecMate (https://secmate.dev). + +Now fixed. +--- + src/coap_oscore.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +Index: libcoap3-4.3.4/src/coap_oscore.c +=================================================================== +--- libcoap3-4.3.4.orig/src/coap_oscore.c 2025-12-21 11:31:09.770810847 +0100 ++++ libcoap3-4.3.4/src/coap_oscore.c 2025-12-21 11:31:09.766810814 +0100 +@@ -1675,6 +1675,7 @@ + const char *kend; + const char *split; + size_t i; ++ size_t len; + + retry: + kend = end = memchr(begin, '\n', size); +@@ -1751,9 +1752,10 @@ + value->u.value_str.length = end - begin; + break; + case COAP_ENC_BOOL: +- if (memcmp("true", begin, end - begin) == 0) ++ len = (size_t)(end - begin); ++ if (len == 4 && memcmp("true", begin, len) == 0) + value->u.value_int = 1; +- else if (memcmp("false", begin, end - begin) == 0) ++ else if (len == 5 && memcmp("false", begin, len) == 0) + value->u.value_int = 0; + else + goto bad_entry; +@@ -1768,7 +1770,7 @@ + coap_log_warn("oscore_conf: Unrecognized configuration entry '%.*s'\n", + (int)(end - begin), + begin); +- return 0; ++ return -1; + } + + #undef CONFIG_ENTRY +@@ -1840,6 +1842,7 @@ + coap_str_const_t keyword; + oscore_value_t value; + coap_oscore_conf_t *oscore_conf; ++ int split_ok = -1; + + oscore_conf = coap_malloc_type(COAP_STRING, sizeof(coap_oscore_conf_t)); + if (oscore_conf == NULL) +@@ -1858,7 +1861,7 @@ + oscore_conf->break_recipient_key = 0; + + while (end > start && +- get_split_entry(&start, end - start, &keyword, &value)) { ++ (split_ok = get_split_entry(&start, end - start, &keyword, &value)) > 0) { + size_t i; + size_t j; + +@@ -1944,6 +1947,8 @@ + goto error; + } + } ++ if (split_ok == -1) ++ goto error; + if (!oscore_conf->master_secret) { + coap_log_warn("oscore_conf: master_secret not defined\n"); + goto error; diff -Nru libcoap3-4.3.4/debian/patches/CVE-2025-65501+65500+65499+65498+65497+65496+65495+65494+65493.patch libcoap3-4.3.4/debian/patches/CVE-2025-65501+65500+65499+65498+65497+65496+65495+65494+65493.patch --- libcoap3-4.3.4/debian/patches/CVE-2025-65501+65500+65499+65498+65497+65496+65495+65494+65493.patch 1970-01-01 01:00:00.000000000 +0100 +++ libcoap3-4.3.4/debian/patches/CVE-2025-65501+65500+65499+65498+65497+65496+65495+65494+65493.patch 2025-12-21 13:59:39.000000000 +0100 @@ -0,0 +1,390 @@ +From cedaa4e99f6dbcb193e4f191c842ed193d83974b Mon Sep 17 00:00:00 2001 +From: Jon Shallow <[email protected]> +Date: Fri, 19 Sep 2025 15:55:17 +0100 +Subject: [PATCH] coap_openssl.c: Check return values in case internal OpenSSL + issue + +--- + src/coap_openssl.c | 201 ++++++++++++++++++++++++++++++--------------- + src/coap_session.c | 4 + + 2 files changed, 137 insertions(+), 68 deletions(-) + +Index: libcoap3-4.3.4/src/coap_openssl.c +=================================================================== +--- libcoap3-4.3.4.orig/src/coap_openssl.c 2025-12-21 13:15:37.190200971 +0100 ++++ libcoap3-4.3.4/src/coap_openssl.c 2025-12-21 13:59:37.803631642 +0100 +@@ -304,7 +304,7 @@ + return dtls_log_level; + } + +-typedef struct coap_ssl_st { ++typedef struct coap_ssl_data { + coap_session_t *session; + const void *pdu; + unsigned pdu_len; +@@ -368,7 +368,7 @@ + int ret = 0; + coap_ssl_data *data = (coap_ssl_data *)BIO_get_data(a); + +- if (data->session) { ++ if (data && data->session) { + if (!coap_netif_available(data->session) + #if COAP_SERVER_SUPPORT + && data->session->endpoint == NULL +@@ -410,10 +410,12 @@ + break; + case BIO_CTRL_SET_CLOSE: + BIO_set_shutdown(a, (int)num); +- ret = 1; + break; + case BIO_CTRL_DGRAM_SET_PEEK_MODE: +- data->peekmode = (unsigned)num; ++ if (data) ++ data->peekmode = (unsigned)num; ++ else ++ ret = 0; + break; + case BIO_CTRL_DGRAM_CONNECT: + case BIO_C_SET_FD: +@@ -429,12 +431,13 @@ + case BIO_CTRL_FLUSH: + case BIO_CTRL_DGRAM_MTU_DISCOVER: + case BIO_CTRL_DGRAM_SET_CONNECTED: +- ret = 1; + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: +- data->timeout = coap_ticks_from_rt_us((uint64_t)((struct timeval *)ptr)->tv_sec * 1000000 + (( +- struct timeval *)ptr)->tv_usec); +- ret = 1; ++ if (data) ++ data->timeout = coap_ticks_from_rt_us((uint64_t)((struct timeval *)ptr)->tv_sec * 1000000 + ++ ((struct timeval *)ptr)->tv_usec); ++ else ++ ret = 0; + break; + case BIO_CTRL_RESET: + case BIO_C_FILE_SEEK: +@@ -463,18 +466,22 @@ + coap_dtls_generate_cookie(SSL *ssl, + unsigned char *cookie, + unsigned int *cookie_len) { +- coap_dtls_context_t *dtls = +- (coap_dtls_context_t *)SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl)); ++ SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); ++ coap_dtls_context_t *dtls = ctx ? (coap_dtls_context_t *)SSL_CTX_get_app_data(ctx) : NULL; + coap_ssl_data *data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(ssl)); +- int r = HMAC_Init_ex(dtls->cookie_hmac, NULL, 0, NULL, NULL); +- r &= HMAC_Update(dtls->cookie_hmac, +- (const uint8_t *)&data->session->addr_info.local.addr, +- (size_t)data->session->addr_info.local.size); +- r &= HMAC_Update(dtls->cookie_hmac, +- (const uint8_t *)&data->session->addr_info.remote.addr, +- (size_t)data->session->addr_info.remote.size); +- r &= HMAC_Final(dtls->cookie_hmac, cookie, cookie_len); +- return r; ++ ++ if (dtls && data) { ++ int r = HMAC_Init_ex(dtls->cookie_hmac, NULL, 0, NULL, NULL); ++ r &= HMAC_Update(dtls->cookie_hmac, ++ (const uint8_t *)&data->session->addr_info.local.addr, ++ (size_t)data->session->addr_info.local.size); ++ r &= HMAC_Update(dtls->cookie_hmac, ++ (const uint8_t *)&data->session->addr_info.remote.addr, ++ (size_t)data->session->addr_info.remote.size); ++ r &= HMAC_Final(dtls->cookie_hmac, cookie, cookie_len); ++ return r; ++ } ++ return 0; + } + + static int +@@ -507,7 +514,7 @@ + const coap_bin_const_t *psk_identity; + + c_session = (coap_session_t *)SSL_get_app_data(ssl); +- if (c_session == NULL) ++ if (c_session == NULL || c_session->context == NULL) + return 0; + o_context = (coap_openssl_context_t *)c_session->context->dtls_context; + if (o_context == NULL) +@@ -588,7 +595,7 @@ + const coap_bin_const_t *psk_key; + + c_session = (coap_session_t *)SSL_get_app_data(ssl); +- if (c_session == NULL) ++ if (c_session == NULL || c_session->context == NULL) + return 0; + + setup_data = &c_session->context->spsk_setup_data; +@@ -646,6 +653,11 @@ + const char *pstr; + int w = where &~SSL_ST_MASK; + ++ if (!session) { ++ coap_dtls_log(COAP_LOG_WARN, ++ "coap_dtls_info_callback: session not determined, where 0x%0x and ret 0x%0x\n", where, ret); ++ return; ++ } + if (w & SSL_ST_CONNECT) + pstr = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) +@@ -727,7 +739,7 @@ + int ret = 0; + coap_session_t *session = (coap_session_t *)BIO_get_data(a); + +- if (out != NULL) { ++ if (session && out != NULL) { + ret =(int)session->sock.lfunc[COAP_LAYER_TLS].l_read(session, (u_char *)out, + outl); + /* Translate layer returns into what OpenSSL expects */ +@@ -752,9 +764,14 @@ + int ret = 0; + coap_session_t *session = (coap_session_t *)BIO_get_data(a); + +- ret = (int)session->sock.lfunc[COAP_LAYER_TLS].l_write(session, +- (const uint8_t *)in, +- inl); ++ if (!session) { ++ errno = ENOMEM; ++ ret = -1; ++ } else { ++ ret = (int)session->sock.lfunc[COAP_LAYER_TLS].l_write(session, ++ (const uint8_t *)in, ++ inl); ++ } + /* Translate layer what returns into what OpenSSL expects */ + BIO_clear_retry_flags(a); + if (ret == 0) { +@@ -1804,6 +1821,14 @@ + X509 *x509; + SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); + ++ if (!ctx) { ++ coap_log_warn("*** setup_pki: (D)TLS: %s: Unable to load " ++ "%s CA Certificate (no ctx)\n", ++ setup_data->pki_key.key.pkcs11.ca, ++ role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); ++ return 0; ++ } ++ + x509 = missing_ENGINE_load_cert( + setup_data->pki_key.key.pkcs11.ca); + if (!x509) { +@@ -1821,8 +1846,9 @@ + X509_free(x509); + return 0; + } +- st = SSL_CTX_get_cert_store(ctx); +- add_ca_to_cert_store(st, x509); ++ st = ctx ? SSL_CTX_get_cert_store(ctx) : NULL; ++ if (st) ++ add_ca_to_cert_store(st, x509); + X509_free(x509); + } else { + FILE *fp = fopen(setup_data->pki_key.key.pkcs11.ca, "r"); +@@ -1838,8 +1864,9 @@ + X509_free(x509); + return 0; + } +- st = SSL_CTX_get_cert_store(ctx); +- add_ca_to_cert_store(st, x509); ++ st = ctx ? SSL_CTX_get_cert_store(ctx) : NULL; ++ if (st) ++ add_ca_to_cert_store(st, x509); + X509_free(x509); + } + } +@@ -1869,7 +1896,7 @@ + for (n = 0; n < san_count; n++) { + const GENERAL_NAME *name = sk_GENERAL_NAME_value(san_list, n); + +- if (name->type == GEN_DNS) { ++ if (name && name->type == GEN_DNS) { + const char *dns_name = (const char *)ASN1_STRING_get0_data(name->d.dNSName); + + /* Make sure that there is not an embedded NUL in the dns_name */ +@@ -1912,18 +1939,23 @@ + + static int + tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) { +- SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, +- SSL_get_ex_data_X509_STORE_CTX_idx()); +- coap_session_t *session = SSL_get_app_data(ssl); +- coap_openssl_context_t *context = +- ((coap_openssl_context_t *)session->context->dtls_context); +- coap_dtls_pki_t *setup_data = &context->setup_data; ++ int index = SSL_get_ex_data_X509_STORE_CTX_idx(); ++ SSL *ssl = index >= 0 ? X509_STORE_CTX_get_ex_data(ctx, index) : NULL; ++ coap_session_t *session = ssl ? SSL_get_app_data(ssl) : NULL; ++ coap_openssl_context_t *context = (session && session->context) ? ++ ((coap_openssl_context_t *)session->context->dtls_context) : NULL; ++ coap_dtls_pki_t *setup_data = context ? &context->setup_data : NULL; + int depth = X509_STORE_CTX_get_error_depth(ctx); + int err = X509_STORE_CTX_get_error(ctx); + X509 *x509 = X509_STORE_CTX_get_current_cert(ctx); +- char *cn = get_san_or_cn_from_cert(x509); ++ char *cn = x509 ? get_san_or_cn_from_cert(x509) : NULL; + int keep_preverify_ok = preverify_ok; + ++ if (!setup_data) { ++ X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNSPECIFIED); ++ OPENSSL_free(cn); ++ return 0; ++ } + if (!preverify_ok) { + switch (err) { + case X509_V_ERR_CERT_NOT_YET_VALID: +@@ -1983,21 +2015,26 @@ + if (setup_data->validate_cn_call_back && keep_preverify_ok) { + int length = i2d_X509(x509, NULL); + uint8_t *base_buf; +- uint8_t *base_buf2 = base_buf = OPENSSL_malloc(length); ++ uint8_t *base_buf2 = base_buf = length > 0 ? OPENSSL_malloc(length) : NULL; + +- /* base_buf2 gets moved to the end */ +- i2d_X509(x509, &base_buf2); +- if (!setup_data->validate_cn_call_back(cn, base_buf, length, session, +- depth, preverify_ok, +- setup_data->cn_call_back_arg)) { +- if (depth == 0) { +- X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); +- } else { +- X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_CA); ++ if (base_buf) { ++ /* base_buf2 gets moved to the end */ ++ i2d_X509(x509, &base_buf2); ++ if (!setup_data->validate_cn_call_back(cn, base_buf, length, session, ++ depth, preverify_ok, ++ setup_data->cn_call_back_arg)) { ++ if (depth == 0) { ++ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); ++ } else { ++ X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_CA); ++ } ++ preverify_ok = 0; + } ++ OPENSSL_free(base_buf); ++ } else { ++ X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNSPECIFIED); + preverify_ok = 0; + } +- OPENSSL_free(base_buf); + } + OPENSSL_free(cn); + return preverify_ok; +@@ -2218,12 +2255,15 @@ + if (setup_data->validate_sni_call_back) { + /* SNI checking requested */ + coap_session_t *c_session = (coap_session_t *)SSL_get_app_data(ssl); +- coap_openssl_context_t *o_context = +- ((coap_openssl_context_t *)c_session->context->dtls_context); ++ coap_openssl_context_t *o_context = (c_session && c_session->context) ? ++ ((coap_openssl_context_t *)c_session->context->dtls_context) : NULL; + const char *sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + size_t i; + char lhint[COAP_DTLS_HINT_LENGTH]; + ++ if (!o_context) ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ + if (!sni || !sni[0]) { + sni = ""; + } +@@ -2821,6 +2861,7 @@ + coap_dtls_context_t *dtls = &((coap_openssl_context_t *)session->context->dtls_context)->dtls; + int r; + const coap_bin_const_t *psk_hint; ++ BIO *rbio; + + nssl = SSL_new(dtls->ctx); + if (!nssl) +@@ -2837,7 +2878,10 @@ + nssl = NULL; + SSL_set_app_data(ssl, session); + +- data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(ssl)); ++ rbio = SSL_get_rbio(ssl); ++ data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; ++ if (!data) ++ goto error; + data->session = session; + + /* hint may get updated if/when handling SNI callback */ +@@ -2969,6 +3013,8 @@ + if (!bio) + goto error; + data = (coap_ssl_data *)BIO_get_data(bio); ++ if (!data) ++ goto error; + data->session = session; + SSL_set_bio(ssl, bio, bio); + SSL_set_app_data(ssl, session); +@@ -3085,10 +3131,12 @@ + coap_dtls_get_timeout(coap_session_t *session, coap_tick_t now COAP_UNUSED) { + SSL *ssl = (SSL *)session->tls; + coap_ssl_data *ssl_data; ++ BIO *rbio; + + assert(ssl != NULL && session->state == COAP_SESSION_STATE_HANDSHAKE); +- ssl_data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(ssl)); +- return ssl_data->timeout; ++ rbio = ssl ? SSL_get_rbio(ssl) : NULL; ++ ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; ++ return ssl_data ? ssl_data->timeout : 1000; + } + + /* +@@ -3116,10 +3164,16 @@ + coap_dtls_context_t *dtls = &((coap_openssl_context_t *)session->context->dtls_context)->dtls; + coap_ssl_data *ssl_data; + int r; ++ BIO *rbio; + + SSL_set_mtu(dtls->ssl, (long)session->mtu); +- ssl_data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(dtls->ssl)); ++ rbio = dtls->ssl ? SSL_get_rbio(dtls->ssl) : NULL; ++ ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; + assert(ssl_data != NULL); ++ if (!ssl_data) { ++ errno = ENOMEM; ++ return -1; ++ } + if (ssl_data->pdu_len) { + coap_log_err("** %s: Previous data not read %u bytes\n", + coap_session_str(session), ssl_data->pdu_len); +@@ -3153,13 +3207,19 @@ + coap_ssl_data *ssl_data; + SSL *ssl = (SSL *)session->tls; + int r; ++ BIO *rbio; + + assert(ssl != NULL); + + int in_init = SSL_in_init(ssl); + uint8_t pdu[COAP_RXBUFFER_SIZE]; +- ssl_data = (coap_ssl_data *)BIO_get_data(SSL_get_rbio(ssl)); ++ rbio = ssl ? SSL_get_rbio(ssl) : NULL; ++ ssl_data = rbio ? (coap_ssl_data *)BIO_get_data(rbio) : NULL; + assert(ssl_data != NULL); ++ if (!ssl_data) { ++ errno = ENOMEM; ++ return -1; ++ } + + if (ssl_data->pdu_len) { + coap_log_err("** %s: Previous data not read %u bytes\n", +Index: libcoap3-4.3.4/src/coap_session.c +=================================================================== +--- libcoap3-4.3.4.orig/src/coap_session.c 2025-12-21 13:15:37.190200971 +0100 ++++ libcoap3-4.3.4/src/coap_session.c 2025-12-21 13:15:37.190200971 +0100 +@@ -1882,6 +1882,10 @@ + coap_session_str(const coap_session_t *session) { + static char szSession[2 * (INET6_ADDRSTRLEN + 8) + 24]; + char *p = szSession, *end = szSession + sizeof(szSession); ++ ++ if (!session) { ++ return "Session not defined"; ++ } + if (coap_print_addr(&session->addr_info.local, + (unsigned char *)p, end - p) > 0) + p += strlen(p); diff -Nru libcoap3-4.3.4/debian/patches/series libcoap3-4.3.4/debian/patches/series --- libcoap3-4.3.4/debian/patches/series 2025-08-27 08:03:02.000000000 +0200 +++ libcoap3-4.3.4/debian/patches/series 2025-12-21 11:30:53.000000000 +0100 @@ -1,2 +1,5 @@ CVE-2024-0962.patch CVE-2024-31031.patch + +CVE-2025-59391.patch +CVE-2025-65501+65500+65499+65498+65497+65496+65495+65494+65493.patch

