# Description Follow-up to the master378 fix in #4678 (CTT: application certificate renewal must use the configured trust stores). Master already ignores the supplied `issuerCertificates` for the default application group (OPC 10000-12 §7.10.5), but it had no regression tests for CA-signed renewals. While adding them I found a real gap: **The validator treated `Bad_CertificateChainIncomplete` as suppressible.** OPC 10000-4 Table 100 (Build Certificate Chain) says: "An error during the chain creation may not be suppressed." §6.1.3 adds: "Processing fails with Bad_SecurityChecksFailed if an element in the chain cannot be found." UpdateCertificate for the application group accepts every *suppressible* error (as §7.10.5 requires). As a result it accepted a renewal signed by a CA that is **not** in the TrustList and was only passed in the ignored issuer list, which is exactly what §7.10.5 rules out. ## Changes - `CertificateValidationCore`: remove `BadCertificateChainIncomplete` from the suppressible status codes. An accept callback (`AcceptError`) is no longer asked about it. - `TrustList`: remove the local workaround that filtered out this error; plain "accept suppressible errors" is now enough. - Docs (`Certificates.md`, `CertificateManager.md`): drop it from the suppressible list, and fix a sample that suppressed it. ## Tests - `ConfigurationNodeManagerPushTests`: - A CA-signed renewal with the CA installed succeeds with a missing, empty, unrelated or malformed issuer list, and the trust stores stay unchanged. - A renewal whose CA is only supplied as an issuer is rejected with `BadCertificateChainIncomplete`; stores and the current certificate are untouched. - End to end on an isolated server: a CA-signed renewal with no issuer list is committed through ApplyChanges. - `ConfigurationNodeManagerPushValidationTests`: the group TrustList validator accepts a CA from the trusted or issuer store and rejects an uninstalled CA. - `CertificateValidationCoreTests` / `CertificateValidatorTest`: - An incomplete chain is unsuppressible and never reaches the callback. - A leaf trusted directly **stays valid when the peer supplies its CA** (§6.1.3: chain certificates "may be provided with the application Certificate"). - One existing test attached its approver only after validating, so it never exercised suppression; it now validates with the approver attached. - Tests that only passed because of the bug (`PushCertificateRequestRegressionTests`, the regenerated-key helper and the rollback test) now install the signing CA in the TrustList first. The two new rejection tests fail on master and pass with this change. ## Reviewer notes / behavior change This was suppressible in 1.5.x as well. Application code whose accept handler approved a CA-signed peer certificate without its CA (CA neither installed nor sent by the peer) will now get a rejection. Without a handler such certificates were already rejected, and the stack's own handlers (`ApplicationInstance`, push validation) never accepted this error. Worth a release note. Local runs (net10.0), all passing: | Suite | Passed | Failed | |---|---|---| | Server.Tests | 8310 | 0 | | Core.Tests (security/transport filter) | 2039 | 0 | | Security.Certificates.Tests | 358 | 0 | | Core.Security.Tests | 558 | 0 | | Client.Tests | 2761 | 0 | | Gds.Tests (PushTest and TrustList tests) | 345 | 0 | The net48 builds of Server.Tests and Core.Tests also succeed. ## Related Issues - Related to #4678 (master378 counterpart) ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [ ] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
7.0 KiB
Migrating from 1.5.378 to 2.0.x
Version 2.0 introduces a major architectural change from pre-generated code files to runtime source generation and more efficient memory use, with several major breaking changes requiring changes to your applications.
This folder includes all of the 1.5.378 → 2.0 migration content as a set of focused sub-documents so you can read only the parts that affect your application. Start with the Migration sub-doc index below to find the sub-doc that matches the symptom you are seeing.
Automate the migration. Add the
OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzeranalyzer package to your projects to receive analyzer warnings and one-click fixes for many of the patterns in these sub-docs. The package implements 26 analyzer rules throughUA0030(excludingUA0013,UA0016,UA0017, and the shim-onlyUA0029) across the index below and the cross-cutting guidance in the Migration Guide.UA0029is currently a runtime-shim/manual marker surfaced throughCS0618, not an analyzer. The type-safety subset (UA0002–UA0008,UA0014,UA0019) maps totypes.md.
Pro TIP. Point your favorite coding agent at the
opcua-v20-migrationskill, which knows when to load each sub-doc and runs the codefixer for you.
Contents
Migration sub-doc index
Find the row that matches the error / API surface you are dealing with and read only the listed sub-doc. The agent skill uses the same table; loading a single sub-doc keeps the context window small.
| When you hit… | Read |
|---|---|
CS0029 / CS1503 / CS0266 on NodeId, Variant, DataValue, ExtensionObject, QualifiedName, LocalizedText, ArrayOf<T> / MatrixOf<T>, ByteString, StatusCode, XmlElement, EnumValue; [Obsolete] warnings on built-in type APIs (analyzers UA0002–UA0008, UA0014, UA0019) |
types.md |
Loggers (Utils.LogX, Utils.Trace), removed static logger helpers (Utils.SetLogger / Utils.SetLogLevel), telemetry context, constructor ITelemetryContext parameter changes, OLD-vs-NEW snippets, fluent DI registration (AddOpcUa().AddLogging().AddMetrics()), breaking-changes inventory, migration utilities |
telemetry.md |
OPCFoundation.NetStandard.Opc.Ua.* package upgrade, TFM changes, Newtonsoft removal |
packages.md |
Source-generated *Collection shims, NodeManager generator, default of boolean properties, project structure |
source-generation.md |
IEncodeableFactoryBuilder, IType, JSON / XML / binary encoders, EncodeableFactory.GlobalFactory, IJsonEncodeable, ComplexTypes namespace move |
encoders.md |
CustomNodeManager, NodeState clone / read / write helpers, OnAfterCreate(CancellationToken), FindChild / CreateChild NodeId assignment, INodeManager3, INodeCache.InvalidateNode, generics on BaseVariableState / BaseVariableTypeState, predefined-node processing, lock (node) on a NodeState, NodeBrowser.DataLock (analyzer UA0027) |
node-states.md |
IUserIdentityTokenHandler, IClientIdentityProvider, IUserTokenAuthenticator, IAccessTokenProvider, ITokenIssuer, IIdentityClaims, caller-supplied secrets, secret store |
identity.md |
CertificateValidator, ref-counted Certificate wrapper, CertificateManager, ICertificateProvider, obsoleted X509Certificate2 direct-exposure APIs, PushManagement transactions (ApplyChanges-gated TrustList updates), caller-owned CertificateStoreIdentifier.OpenStore stores, non-suppressible Bad_CertificateChainIncomplete |
certificates.md |
ApplicationConfiguration changes, Data-Contract serializer removal, MinMetadataSamplingInterval → MinSupportedSamplingInterval, ParseExtension / UpdateExtension signature, session / browser state persistence |
configuration.md |
Session → ManagedSession, V2 subscription engine, GDS-client Task → ValueTask modernisation, removed obsolete GDS APIs, durable subscriptions, PubSub, reverse-connect, server ISubscription publish-pipeline members / SessionPublishQueue internalized (analyzer UA0030) |
sessions-subscriptions.md |
UaPubSubApplication.Create*, IUaPubSubConnection, UaPubSubConfigurator, IUaPublisher, AMQP transport, JsonEncodingMode.Reversible/NonReversible, PubSub JSON encoder changes, DataSetFieldContentMask RawData / timestamp behaviour |
pubsub.md |
AlarmConditionState state-transition behaviour, auto-emitted GeneralModelChangeEvent, ModelChangeAggregator, INodeCache.InvalidateNode triggered by model change |
alarms-model-change.md |
DateTime.UtcNow, Timer, deterministic time in tests; System.TimeProvider adoption |
timeprovider.md |
ITransportListener.Open / Close removed, ReverseConnectManager.StartService / Dispose obsolete, reverse-connect DI/provider migration, custom ITransportListenerFactory / ITransportListenerCertificateRotation implementers need the new async method names |
transport-listener-async.md |
All sub-documents
telemetry.md— Telemetry and Loggingpackages.md— Package, Target Framework, and Dependency Changessource-generation.md— Source Generationtypes.md— Improved Type Safetyencoders.md— Encoders and Complex Typesnode-states.md— Node States andINodeCacheidentity.md— Identity, Token Handlers, and Secretscertificates.md— Certificates andICertificateProviderconfiguration.md— Configuration and State Persistencesessions-subscriptions.md— Sessions, GDS Client, and Subscriptionspubsub.md— PubSub (Part 14): breaking API, transport, JSON, and field-encoding changesalarms-model-change.md— Alarms and Address-Space Model Changestimeprovider.md— Time and Timer Abstraction (TimeProvider)transport-listener-async.md— AsyncITransportListenerAPI (issue #3923)
See also
- Migration Guide landing page — index across
all versions, including the small
1.05.377→1.05.378and1.04→1.05legacy notes. - What's New in 2.0 — narrative tour of the 2.0 changes, grouped by theme and layer.
- Profiles — facet / profile coverage of the 2.0 release.