Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"microsoft.dotnet.apicompat.tool": {
"version": "10.0.301",
"version": "10.0.403",
"commands": [
"apicompat"
],
Expand Down
155 changes: 155 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,161 @@ All notable changes to `credentials-dotnet` are documented here. The format is b
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v1.2.0 - Unreleased

Every dependency moves to its latest stable release, so Credentials is built against the same graph the
rest of the stack resolves (DataProofs 2.0.0, NetDid 4.0.0, NetCrypto 1.7.1, Microsoft.Extensions 10.0.14,
matching `DidComm.Core` 1.5.0). FluentAssertions is the one deliberate exception. Nothing issued by an
earlier Credentials exists in the wild (owner decision), so where DataProofs 2.0.0 changes signed bytes
or proof formats, this release carries no compatibility shims or migration steps.

### Fixed

- **JOSE and SD-JWT signing no longer throw `MissingMethodException` when a newer `DataProofsDotnet.Jose` is
resolved** ([#20](https://github.com/moisesja/credentials-dotnet/issues/20)). 1.1.1 was compiled against
Jose 1.1.0. Jose 1.3.0 replaced `JwsSigner..ctor(ISigner, string)` with
`JwsSigner..ctor(ISigner, string, JwsKidPlacement)`; the added optional parameter keeps source
compatibility but breaks binary compatibility.
- Any application whose graph resolved Jose ≥ 1.3.0 failed at runtime on all four JOSE signing paths:
`vc+jwt` issuance, SD-JWT VC issuance, the holder's SD-JWT Key Binding JWT, and the holder's `vp+jwt`.
Every application that also references `DidComm.Core` ≥ 1.4.1 resolves such a Jose.
- This release is built against DataProofs 2.0.0. The JOSE signed bytes are unchanged: the default
`JwsKidPlacement.Auto` keeps the `kid` in the integrity-protected header for the JWT, SD-JWT and KB-JWT
media types, and a regression test pins this for every token Credentials emits.
- DataProofs states that it does not guarantee binary compatibility across minor versions, so each move
of the DataProofs floor needs a Credentials rebuild and release.

### Security

- **Inherited from DataProofs 2.0.0: the proof members a verifier acts on are bound to the signature**
([GHSA-6fxh-mc39-94vc](https://github.com/moisesja/dataproofs-dotnet/security/advisories/GHSA-6fxh-mc39-94vc)).
An RDFC or bbs-2023 signature covers the RDF a proof expands to, not its JSON, and `@context` is not
signed, so with DataProofs ≤ 1.5.0 anyone holding a proof could respell `expires`, `challenge`,
`domain` or `proofPurpose` through a context and have the verifier read a value the issuer never signed.
The RDFC and bbs-2023 suites now verify only if the members they read (`id`, `type`, `cryptosuite`,
`created`, `expires`, `verificationMethod`, `proofPurpose`, `challenge`, `domain`, `nonce`,
`previousProof`) are what was signed; a renamed-away or never-signed member fails with
`PROOF_VERIFICATION_ERROR`. Some spec-legal but unverifiable proof shapes are newly refused (a context
mapping a modeled member to another predicate, a proof without exactly one `rdf:type`, a compact-IRI
`verificationMethod`, a non-canonical `proofPurpose` spelling). The JCS suites, JOSE, COSE and SD-JWT
sign the JSON itself and were never affected. DataProofs also hardened RDFC canonicalization against
hostile blank-node graphs (a stack overflow that ended the process; permutation blow-ups) with a work
budget that refuses pathological input in about 50 ms.
- **Inherited from DataProofs 1.5.0: RDFC proofs now fail closed on JSON-LD data loss.** Before, whatever
RDF canonicalization silently dropped or respelled was not signed, so a holder could change it without
breaking an `eddsa-rdfc-2022` / `ecdsa-rdfc-2019` / `bbs-2023` proof. That included every custom claim of
a credential whose only context was credentials/v2, which has no `@vocab`.
- Issuance now refuses such a document with `InvalidOperationException` (see Changed).
- Verification fails it with `DATA_LOSS_DETECTION_ERROR`: proof check Failed, decision Rejected.
- Also fixed upstream: two bbs-2023 issues that let a holder alter disclosed data, and RDFC proofs over
credentials/v1 (without `https://w3id.org/security/data-integrity/v2`) that left the proof
configuration unsigned.
- The JCS suites, JOSE, COSE and SD-JWT never used JSON-LD processing and are unaffected.
- **`Microsoft.SourceLink.GitHub` bumped 10.0.300 → 10.0.403** to resolve
[GHSA-23fw-v26w-5fgq](https://github.com/advisories/GHSA-23fw-v26w-5fgq) in its `Microsoft.Build.Tasks.Git`
dependency. With `TreatWarningsAsErrors`, the `NU1902` audit warning failed restore and broke every CI run
on `main` from 2026-09. SourceLink is used only at build time (`PrivateAssets=All`) and never ships to
consumers.

### Changed

- **Dependencies, all at the latest stable release:**

| Package | From | To |
|---|---|---|
| `DataProofsDotnet.Core` / `.Jose` / `.Cose` / `.Rdfc` / `.Extensions.DependencyInjection` | 1.1.0 | **2.0.0** |
| `NetDid.Core` / `.Method.Key` / `.Extensions.DependencyInjection` | 2.3.0 | **4.0.0** |
| `NetCrypto` | 1.2.0 | **1.7.1** |
| `JsonSchema.Net` | 7.3.2 | **9.6.0** |
| `Microsoft.Extensions.*` | 10.0.8 | **10.0.14** (required: NetDid 4.0.0 needs at least this) |
| `Microsoft.SourceLink.GitHub` (build-only) | 10.0.300 | **10.0.403** |
| `AngleSharp` pin (`Credentials.Rdfc`) | 1.5.2 | **removed** (`DataProofsDotnet.Rdfc` itself requires the patched ≥ 1.6.0) |

Development-only packages also moved to latest: PublicApiAnalyzers 5.6.0, Microsoft.NET.Test.Sdk 18.11.0,
xunit.runner.visualstudio 4.0.1, NSubstitute 6.2.0, coverlet 10.1.0, Xunit.SkippableFact 1.5.85, and the
ApiCompat tool 10.0.403. **FluentAssertions stays at 7.0.0**, the last release under the free Apache-2.0
licence. It is test-only.

**Applications pinned to older DataProofs (< 2.0.0) or NetDid (< 4.0.0) should stay on Credentials
1.1.1.** Upgrading raises those floors. DataProofs 2.0.0's RDFC suite constructors changed shape, so
this release is rebuilt against it (an assembly built against 1.5.0 throws `MissingMethodException`).
- **RDFC issuance and verification are stricter** (from DataProofs 1.5.0, above).
- **Credentials issued earlier with RDFC over undefined terms no longer verify**, including ones
Credentials ≤ 1.1.1 issued.
- To keep custom claims, define the terms in a context, or list
`https://www.w3.org/ns/credentials/undefined-terms/v2` last in `@context` (VCDM 2.0 §5.2). That context
is bundled offline, and the RDFC sample now does this.
- IRIs must be well formed, absolute and normalized.
- **Language value objects with a base direction (`@direction`) are signed under the RDFC suites**
(from DataProofs 2.0.0, resolving
[dataproofs-dotnet#40](https://github.com/moisesja/dataproofs-dotnet/issues/40)). RDFC canonicalizes
with JSON-LD 1.1 `rdfDirection: i18n-datatype`, the representation the reference Data Integrity
implementations sign with, so the direction is inside the signature: flipping `ltr`/`rtl` or dropping
the direction after signing fails the proof with `PROOF_VERIFICATION_ERROR`. Earlier versions signed
`ltr` and `rtl` as the same bytes, and DataProofs 1.5.0 refused `@direction` outright. A number or
boolean with `@direction` is still refused as data loss. Tests cover the four W3C positions (`name`,
`description`, `issuer.name`, `issuer.description`) under both RDFC and JCS.
- **RDFC signed bytes changed for some documents** (DataProofs 2.0.0 corrected tied-blank-node labelling
and Unicode code-point ordering to match `rdf-canonize`). Ordinary credentials without tied blank
nodes are unaffected; a document with two same-looking unnamed objects now canonicalizes to the
reference implementation's bytes.
- **bbs-2023 follows the reference algorithms** (DataProofs 2.0.0): proofs now interoperate with the
reference implementation, and the W3C `derivedRevealDocument.json` vector verifies. Base and derived
proofs from earlier versions are not compatible. New limitation: a derivation must reveal at least one
non-mandatory claim (NetCrypto's BBS provider cannot prove a mandatory-only disclosure); `IBbsDeriver`
refuses such a request with `CredentialFormatException`, and its message now carries the substrate's
specific cause (an invalid pointer, a malformed base, or the mandatory-only case) instead of a generic
sentence. A reveal pointer that matches nothing in the document is now refused too (the reference
selection algorithm's behaviour); 1.5.0 silently revealed nothing for it. Documents with `@list` values
or language maps are refused at derivation.
- **W3C VCDM 2.0 conformance: 57 → 58 of 59.** The `type` term-resolution case, a documented gap, now
passes for RDFC-secured input; `relatedResource` digest verification remains the one named gap. The
gate no longer relies on a pass count alone: every failing suite test must be one of the **named**
known failures in `W3cVcdm2SuiteTests`, so a regression cannot hide behind the count. See
`docs/conformance.md`.
- The `InvalidOperationException` thrown when a document cannot be secured now includes the specific
cause from the substrate (for example "uses @direction"), not only the generic data-loss sentence.
- **Issuance keeps its documented exception contract.** Since DataProofs 1.4.0, proof creation reports input
problems with its own `ProofGenerationException`. `IIssuer.IssueAsync` and
`IHolder.BindWithDataIntegrityAsync` now rethrow it as the documented `InvalidOperationException`, keeping
the original as `InnerException`, so no DataProofs type escapes the public API. The message names the
cryptosuite and the cause without quoting the document. The `InnerException` chain keeps the substrate
detail, which can include context URLs or IRIs from the caller's own document.
- **More malformed inputs are definitive failures** (from DataProofs 1.4.0). Malformed UTF-8 or an unpaired
surrogate in a JOSE header, an SD-JWT disclosure, the issuer JWT or KB-JWT, or a Data Integrity document
now ends **Failed** (Rejected) instead of Indeterminate. A compact JWS header with an invalid-UTF-8 member
name, which used to verify, now fails.
- **DID resolution is stricter** (NetDid 3.0–4.0). DID syntax is checked more tightly, DID documents that
break DID Core fail to resolve, and a verification method must have a `controller`. A resolution error is
Indeterminate in Credentials, as before. No did:key verdict changes.
- **JSON Schema validation runs on JsonSchema.Net 9** (9.6.0).
- Each validation uses its own schema and dialect registries. A schema supplied with one credential can
never answer another credential's `$ref`, and it can never redefine a custom `$schema` dialect for
later validations. The same `$id` can be validated repeatedly.
- No external reference is ever fetched, even if other code in the process installs a fetcher on
JsonSchema.Net's global registry.
- Structurally invalid schemas stay Indeterminate (`schema.unparseable`) rather than throwing; this
includes a non-string `$schema` and a lone-surrogate escape in a keyword value. An unknown `$schema`
dialect now also reports `schema.unparseable` (it used to be `schema.evaluation_error`); both are
Indeterminate.
- A schema without `$schema` is evaluated as 2020-12. A declared `$schema` selects a dialect JsonSchema.Net
knows, or one the same document defines. For draft-07 schemas, keywords beside `$ref` are now evaluated
rather than ignored, which is stricter.
- A pathological `pattern` is still cut off by the per-match regex timeout. New tests pin all of these
properties.
- **ES256K signatures can be re-encoded** (from NetCrypto 1.5.0). ES256K verification accepts high-S
signatures: for an ES256K `vc+jwt`, `vc+cose`, SD-JWT VC, KB-JWT or `vp+jwt`, the same token with its
signature `S` replaced by `n − S` now verifies. P-256 tokens always behaved this way.
- A re-encoded token never gets a result the original could not. Credentials checks freshness against
signed content (`nonce` / `aud` / `sd_hash` / challenge) and never keys on signature bytes.
- **Applications that key replay caches, deduplication or credential identity on token bytes, or a hash
of them, should key on signed content instead** (`jti`, nonce, credential `id`).

**No public API change.** All three packages pass ApiCompat against the 1.1.1 baseline, and the default
(`Credentials.Core` / `Credentials.Extensions.DependencyInjection`) consumer graph is still free of
Newtonsoft. This is a minor release, not a patch, because the dependency floors rise and verification
narrows.

## v1.1.1 - 7/20/2026

### Security
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CredentialsVersion>1.1.1</CredentialsVersion>
<CredentialsVersion>1.2.0</CredentialsVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Deterministic>true</Deterministic>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
Expand Down
Loading
Loading