Canonical Resource Management Infrastructure Implementation Guide, published by HL7 International / Clinical Decision Support. This guide is not an authorized publication; it is the continuous build for version 2.0.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/crmi-ig/ and changes regularly. See the Directory of published versions
| Page standards status: Trial-use |
Digital signatures provide cryptographic proof of authenticity, integrity, and non-repudiation for FHIR knowledge artifacts. This page describes how CRMI knowledge artifacts align with the FHIR Digital Signatures specification and addresses specific considerations for canonical resource management.
Background
Healthcare organizations frequently implement clinical decision support (CDS) rules, guidelines, measures, and assessments that are developed by third-party organizations, academic institutions, or commercial vendors. These knowledge artifacts often contain proprietary algorithms, evidence-based recommendations, or specialized clinical content that is protected by copyright and distributed under specific licensing terms.
Scenario
A large healthcare system is implementing a comprehensive sepsis detection and management protocol developed by a renowned medical research institution. The protocol includes:
The research institution distributes it under a specific license that:
The Problem
Without proper artifact signing and integrity verification:
The Solution: Digital Signing
By digitally signing artifacts, institutions can:
This implementation guide follows the FHIR Digital Signatures specification (R6 Ballot), which defines:
The FHIR specification describes several methods for associating signatures with signed content:
For Document Bundles, signatures are commonly embedded within the Bundle structure:
Provenance.target references exactly Bundle/[id] (where [id] is the Bundle's id value) to indicate it signs the BundleProvenance.signature element contains the detached signature of the Bundle with all Provenance entries that themselves contain embedded signatures removed from the entry list before canonicalization (i.e., remove entries whose resource is a Provenance with a target referencing Bundle/[id])Clarification: While the signature data itself is "detached" (the payload is omitted from the JWS/XML signature), the Provenance resource carrying the signature is "embedded" within the Bundle structure. This is the recommended approach for signing Bundles.
Note: The
Bundle.signatureelement is deprecated in the FHIR specification. Applications SHALL use the Provenance-embedded approach described above.
For non-Bundle resources or when signatures need to be managed separately:
X-Provenance: [provenance-url]Link: <[provenance-url]>; rel="provenance"Recommendation: To improve interoperability and align with web standards, implementers SHOULD support the standard Link header as an alternative to or in addition to the custom X-Provenance header.
The FHIR specification defines several canonicalization methods to balance security and practicality:
| Canonicalization | Description | Use Case |
|---|---|---|
http://hl7.org/fhir/canonicalization/json |
Full resource (RFC 8785) | Maximum integrity verification |
http://hl7.org/fhir/canonicalization/json-xml |
JSON canonicalization with XHTML pre-canonicalized per XML rules | Use when the resource lifecycle may include XML representation |
http://hl7.org/fhir/canonicalization/json#data |
Excludes Resource.text |
Signs structured data only |
http://hl7.org/fhir/canonicalization/json#static |
Excludes Resource.text and Resource.meta |
Allows resource mobility across servers |
http://hl7.org/fhir/canonicalization/json#narrative |
Only Resource.id and Resource.text |
Human attestation of narrative |
http://hl7.org/fhir/canonicalization/json#document |
Omits Bundle.id and Bundle.metadata |
Signing Document Bundles that may be copied across servers |
For CRMI knowledge artifacts, the #static variant is recommended as it excludes metadata that changes during resource management while preserving the substantive content. When signing Document Bundle artifacts that may be distributed across servers, the #document variant should be considered. If the artifact may ever be represented as XML, use the json-xml canonicalization instead of plain json.
Note on XML canonicalization: The FHIR specification also defines an XML canonicalization method (
http://hl7.org/fhir/canonicalization/xml, based on Canonical XML 1.1) for resources represented as XML. See FHIR Digital Signatures §6.1.2.2.3 for details. CRMI primarily profiles JWS/JSON signatures, but implementations MAY use XML Digital Signatures following the rules in §6.1.2.2.7.
A single Provenance resource may sign multiple CRMI artifacts by listing them all in Provenance.target. When computing the JWS signature over multiple target resources, the canonicalized resources are placed in a JSON Array in the same order as Provenance.target, and the array itself is canonicalized per RFC 8785. This allows, for example, a Library and its dependent ValueSets to be signed together with a single Provenance.
Implementer note: The code shown throughout this page is pseudo-code and intended to be informative.
A CRMI Knowledge Artifact Server that supports signing will need to implement:
/.well-known/jwks.json endpoint to expose public signing keysCanonicalize the resource according to the chosen canonicalization method. For CRMI artifacts using the #static variant:
// Create a copy and exclude meta and text elements
let resourceCopy = deepCopy(resource)
delete resourceCopy.text
delete resourceCopy.meta
// Canonicalize according to RFC 8785 (JSON Canonicalization Scheme)
let canonicalJson = canonicalizeJson(resourceCopy)
Create a JWS detached signature:
// The payload is the canonicalized resource
let payload = base64url(canonicalJson)
// Create JWS with detached payload (payload is omitted from the JWS)
let jws = createJWS({
protectedHeader: {
alg: 'RS256',
typ: 'JOSE',
sigT: new Date().toISOString(),
canon: 'http://hl7.org/fhir/canonicalization/json#static',
x5c: [certificateChain], // or use 'kid' for key reference
srCms: [{
commId: {
id: 'urn:oid:1.2.840.10065.1.12.1.1',
desc: "Author's Signature"
}
}]
},
payload: payload, // This is used for signing but omitted from output
privateKey: signingKey
})
// Result is: base64url(header) + ".." + base64url(signature)
// Note the empty payload section
Note on purpose of signature: Per FHIR 6.1.2.2.6, the
srCmssigner commitments property in the JWS protected header (shown above) satisfies the SHALL requirement to include the purpose of signature. When the signature is carried in a Provenance resource,Signature.type,Signature.when, andSignature.whoSHOULD NOT be set (see 6.1.2.2.8), as those values are already expressed inProvenance.agent.type,Provenance.occurredDateTime, andProvenance.agent.who.
Create a Provenance resource to carry the signature:
{
"resourceType": "Provenance",
"id": "example-signature",
"target": [{
"reference": "ActivityDefinition/example"
}],
"occurredDateTime": "2025-10-21T10:00:00Z",
"recorded": "2025-10-21T10:00:00Z",
"agent": [{
"type": {
"coding": [{
"system": "urn:iso-astm:E1762-95:2013",
"code": "1.2.840.10065.1.12.1.1",
"display": "Author's Signature"
}]
},
"who": {
"identifier": {
"system": "http://example.org/certificates",
"value": "CN=Example Authority"
}
}
}],
"signature": [{
"targetFormat": "application/fhir+json;canonicalization=http://hl7.org/fhir/canonicalization/json#static",
"sigFormat": "application/jose",
"data": "[base64-encoded-jws]"
}]
}
For Bundles: Include the Provenance resource as an entry in the Bundle.
For individual resources:
Reference the Provenance using headers. Servers SHOULD include both the standard Link header and the X-Provenance header for maximum client compatibility:
Link: <https://example.org/fhir/Provenance/example-signature>; rel="provenance"
X-Provenance: https://example.org/fhir/Provenance/example-signature
A client verifying a signed FHIR knowledge artifact should:
target referencing Bundle/[id]Link or X-Provenance headerslet signature = provenance.signature[0]
let jwsData = signature.data // base64-encoded JWS
let targetFormat = signature.targetFormat
let canonicalization = extractCanonicalization(targetFormat)
// Apply the same canonicalization used during signing
let resourceCopy = deepCopy(resource)
if (canonicalization.includes('#static')) {
delete resourceCopy.text
delete resourceCopy.meta
} else if (canonicalization.includes('#data')) {
delete resourceCopy.text
}
let canonicalJson = canonicalizeJson(resourceCopy)
let payload = base64url(canonicalJson)
// Parse the JWS
let [headerB64, , signatureB64] = jwsData.split('.')
let header = JSON.parse(base64urlDecode(headerB64))
// Retrieve the public key
let publicKey = await getPublicKey(header) // from x5c or kid
// Reconstruct and verify
let signatureInput = headerB64 + '.' + payload
let isValid = verifySignature(signatureInput, signatureB64, publicKey, header.alg)
if (!isValid) {
throw new Error("Signature verification failed")
}
// Verify the certificate chain against a trusted CA
let certificate = parseCertificate(header.x5c[0])
let isTrusted = verifyCertificateChain(certificate, trustedCAs)
if (!isTrusted) {
throw new Error("Certificate verification failed")
}
A successful validation confirms:
This example demonstrates signing an individual ActivityDefinition resource with an externally referenced Provenance resource.
{
"resourceType": "ActivityDefinition",
"id": "example-activity",
"url": "http://example.org/ActivityDefinition/example-activity",
"version": "1.0.0",
"status": "active",
"description": "Example activity definition",
"kind": "Task"
}
When retrieved, the resource includes both Link and X-Provenance headers:
HTTP/1.1 200 OK
Content-Type: application/fhir+json
Link: <https://example.org/fhir/Provenance/activity-signature>; rel="provenance"
X-Provenance: https://example.org/fhir/Provenance/activity-signature
{
"resourceType": "ActivityDefinition",
"id": "example-activity",
"url": "http://example.org/ActivityDefinition/example-activity",
"version": "1.0.0",
"status": "active",
"description": "Example activity definition",
"kind": "Task"
}
Retrieved from https://example.org/fhir/Provenance/activity-signature:
{
"resourceType": "Provenance",
"id": "activity-signature",
"target": [{
"reference": "ActivityDefinition/example-activity"
}],
"occurredDateTime": "2025-10-21T10:00:00Z",
"recorded": "2025-10-21T10:00:00Z",
"agent": [{
"type": {
"coding": [{
"system": "urn:iso-astm:E1762-95:2013",
"code": "1.2.840.10065.1.12.1.1"
}]
},
"who": {
"display": "Example CRMI Server",
"identifier": {
"system": "http://example.org/certificates",
"value": "CN=crmi.example.org"
}
}
}],
"signature": [{
"targetFormat": "application/fhir+json;canonicalization=http://hl7.org/fhir/canonicalization/json#static",
"sigFormat": "application/jose",
"data": "eyJ0eXAiOiJKT1NFIiwiYWxnIjoiUlMyNTYiLCJzaWdUIjoiMjAyNS0xMC0yMVQxMDowMDowMFoiLCJjYW5vbiI6Imh0dHA6Ly9obDcub3JnL2ZoaXIvY2Fub25pY2FsaXphdGlvbi9qc29uI3N0YXRpYyJ9..dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}]
}
This approach allows:
For signatures that must remain valid over extended periods:
When signing keys are rotated: