Require serialized PKCS#11 handles and the specified four-byte key nonce before copying key material into the TPM channel context. This rejects incompatible raw SKS keys and prevents out-of-bounds reads from undersized inputs.
The OpenSSL HMAC-SHA1/SHA256 verify helpers compared the recomputed
MAC against the peer-supplied signature with UA_ByteString_equal(),
which reduces to a plain memcmp(). memcmp() carries no constant-time
guarantee and, on a byte-at-a-time implementation (the norm on the
small-footprint libcs open62541 is routinely built against), returns
as soon as it finds a differing byte -- a timing side channel a
remote peer can use to recover a valid MAC byte-by-byte.
Switch to UA_constantTimeEqual(), already used correctly by every
other symmetric SecurityPolicy (mbedTLS Basic128Rsa15, Basic256,
Basic256Sha256, Aes128Sha256RsaOaep). Since it takes a single length
and reads that many bytes from both buffers, first validate
signature->length against the expected MAC length, mirroring the
pattern used by the project's mbedTLS RSA policy Verify functions.
The digest length is fixed by the algorithm and policy, not attacker
data, so this early-return introduces no new timing side channel.
Internal Vulnerability Advisory: open62541-SA-2026-0038
Co-authored-by: Luigi Colluto <gigioneggiando@users.noreply.github.com>
encrypt_sp_pubsub_aes128ctr_tpm/decrypt_sp_pubsub_aes128ctr_tpm and their
AES-256-CTR counterparts computed the block-aligned processing size
(sizeToEncrypt/sizeToDecrypt) by rounding data->length up to the next
16-byte boundary, but stored the result in a CK_BYTE. Two distinct bugs
followed from this:
- For a data->length whose rounded-up value exceeds 255, the 8-bit value
wraps around, so far fewer bytes than intended are processed while the
function still returns UA_STATUSCODE_GOOD.
- For any data->length that is not itself a multiple of 16, the rounded-up
size is larger than the caller's actual buffer. The PKCS#11 update calls
then read block-sized chunks directly from data->data past its end, and
the final loop that copies the result back writes that same rounded-up
size into data->data, overflowing the caller's allocation.
AES-CTR is a stream cipher and never needs block-aligned input. Fix this
by processing exactly data->length bytes throughout, using size_t/CK_ULONG
for all lengths instead of CK_BYTE: each PKCS#11 update call is chunked at
MAX_ENCRYPTION_SIZE bytes with a shorter final chunk when data->length is
not itself a multiple of it, operating on the caller's buffer directly
with no rounding, no padding, and no risk of the output exceeding the
caller's allocation.
Co-authored-by: Luigi Colluto <gigioneggiando@users.noreply.github.com>
Internal Vulnerability Advisory: open62541-SA-2026-0033
UA_DataValue_backend_copyRange() performed a shallow memcpy of the
source UA_DataValue before attempting the range copy. Because the
destination's UA_Variant fields were not reinitialized first, a
failing UA_Variant_copyRange() (for example when the client-supplied
indexRange exceeds UA_MAX_ARRAY_DIMS) left the destination value as an
uninitialized alias of the backend-owned storage instead of an
independent copy.
copyDataValues_backend_memory() also discarded the status code from
both UA_DataValue_backend_copyRange() and UA_DataValue_copy(), so the
aliased, partially-copied value was still counted as a successful
result and forwarded to the HistoryRead response. Freeing that
response later released the backend's live storage, leaving the
backend with a dangling pointer that was dereferenced on a subsequent
HistoryRead.
Reinitialize the destination variant before the range copy and clear
it again on failure, mirroring the safe pattern already used by
UA_DataValue_copyRange(). Propagate copy failures out of
copyDataValues_backend_memory() immediately instead of counting a
failed entry as provided.
Internal Vulnerability Advisory: open62541-SA-2026-0021
Co-authored-by: gff-cw <gff-cw@users.noreply.github.com>
In getHistoryData_service_default(), the outer continuation point encodes
a skip count that was read directly from client-controlled bytes without
validation. Two independent arithmetic errors could cause a heap-buffer-
overflow in the subsequent backend copy call:
1. When skip > _resultSize, the subtraction `_resultSize - skip` wraps
around in size_t, producing a very large value. After clamping to
maxSize, the allocation is correct, but the wrapped large skip is
still used to recompute valueSize for the backend call.
2. When the reconstructed valueSize exceeds the number of entries actually
allocated in outResult, copyDataValues() writes beyond the end of the
result array (heap-buffer-overflow write).
Fix both issues in getHistoryData_service_default():
- Reject continuation points whose skip value exceeds the computed result
set size, returning UA_STATUSCODE_BADCONTINUATIONPOINTINVALID.
- After computing valueSize, cap it to the remaining allocated capacity in
outResult so the backend cannot be instructed to write past the buffer.
Internal Vulnerability Advisory: open62541-SA-2026-0027
The default server configuration zero-initialises
maxPublishReqPerSession, which disables the per-session cap on
outstanding PublishRequest entries. A remote client that is allowed
to create a session and a subscription can therefore send an
unbounded number of PublishRequest messages, each of which allocates
a UA_PublishResponseEntry and appends it to the session's publish
queue. The resulting monotonic heap growth causes process memory
exhaustion and a denial of service.
Set a safe finite default of 512 outstanding PublishRequests per
session in setDefaultConfig() so that the cap is enforced out of the
box, while still allowing deployers to override it.
Internal Vulnerability Advisory: open62541-SA-2026-0010
Co-Authored-By: keyme <kmm2003@users.noreply.github.com>
Replace the builtin method with manual classification. We now require
the KU_CRL_SIGN flag to detect a CA. Before we rejected the leaf
certificates generated by some vendors.
Walk the tree to find a complete chain of unrevoked and current
certificates. The chain must end in a self-signed certificate.
Then, on the "way down", check that at least one certificate
in the chain is trusted.
The previous certificate verification relied on many OpenSSL internals
and a forest of feature-flags. The new code is about the same size and
makes the certificate verification steps explicit.
The only downside is that we no longer auto-retrieve revocation lists if
a distribution point is defined in a CA certificate. But revocation is
handled by a GDS in OPC UA. And we don't want our certificate
verification to do synchronous HTTP calls in the background.
If a chain of Certificate Authorities (CAs) longer than one is present,
all CRL checks on the additional CAs were bypassed. This resulted in the
potential acceptance of certificates that have been revoked or have
expired CRLs.
Username password validation in access control plugin allows only
passwords stored in plaintext. Add a callback to implement custom
validation. This allows salted password hashes and timing safe
comparison in the server. Furthermore remote validation could be
implemented. The new function UA_AccessControl_defaultWithLoginCallback()
calls existing UA_AccessControl_default() and after that installs
the given UA_UsernamePasswordLoginCallback with context.
* In UA_CertificateVerification_VerifyApplicationURI()
set initial subjectURI to UA_STRING_NULL, may be no urn entry in certificate
* Fix problem, if UA_OpenSSL_LoadCertificate() fails in UA_ChannelModule_New_Context()
The constant string arrays logLevelNames and logCategoryNames are not
exported neither in header include nor in dynamic library. But they
appear in static libopen62541.a library and my create conflicts.
Declare these symbols static to keep them local in ua_log_stdout.c .
* Add OpenSSL3.0 support
This change set adds a new function UA_OpenSSL_RSA_Key_Size() to get
the RSA key size, re-writes the function
UA_Openssl_RSA_Private_Decrypt() by using the high level APIs of
OpenSSL3.0, add a new function UA_RSA_Generate_Key() to generate
a RSA key.
No build warning with OpenSSL3.0 and OpenSSL1.1.1f.
* Build & Test with OpenSSL3.0 in Ubuntu22.04
* Add OpenSSL3.0 support
This change set adds a new function UA_OpenSSL_RSA_Key_Size() to get
the RSA key size, re-writes the function
UA_Openssl_RSA_Private_Decrypt() by using the high level APIs of
OpenSSL3.0, add a new function UA_RSA_Generate_Key() to generate
a RSA key.
No build warning with OpenSSL3.0 and OpenSSL1.1.1f.
* Build & Test with OpenSSL3.0 in Ubuntu22.04
* fix(core): DataValue statuscodes checks ignore additional information bits
* fix(core): Update UA_StatusCode_name to use UA_StatusCode_equal
* fix(core): rename UA_StatusCode_equal to UA_StatusCode_isEqualTop and update function docs
* fix(core): changed statuscode message invlaid status code value to real invalid statuscode
* fix(core): fix windows clang build