2026-04-16·15 min read·

NIS2 Art.21(2)(h): Cryptography and Encryption Policy — Developer Implementation Guide (2026)

Most NIS2 compliance guides treat cryptography as a checkbox — "use TLS, encrypt at rest, done." Art.21(2)(h) of the NIS2 Directive sets a significantly higher bar. It requires essential and important entities to adopt documented cryptography and encryption policies covering algorithm selection, key management, and the evidence trail that NCA auditors will expect from June 2026 onward.

For SaaS teams, cloud infrastructure engineers, and developers building EU-regulated systems, Art.21(2)(h) means your cryptographic decisions — which algorithms you use, how you manage keys, how you handle deprecated ciphers — are now regulatory matters, not just engineering preferences.

This guide translates the legal text into concrete implementation requirements.


1. What Art.21(2)(h) Actually Requires

NIS2 Directive 2022/2555, Art.21(2)(h) states that entities must adopt measures addressing "the use of cryptography and, where appropriate, encryption."

Recital 79 of the Directive provides interpretive context: cryptography policies must be risk-appropriate, documented, and aligned with recognised standards. ENISA's technical guidance identifies the following components of a compliant cryptography policy:

The Four Components NCAs Will Assess

ComponentWhat Regulators ExamineEvidence Required
Algorithm selection policyApproved/prohibited cipher lists, version constraintsWritten policy, technology register
Key management lifecycleGeneration, storage, rotation, destructionKey management procedure document
Certificate managementCA trust store, renewal automation, revocation handlingCertificate inventory, renewal logs
Cryptographic agilityPlan for migrating deprecated algorithmsMigration roadmap, post-quantum assessment

The June 2026 NCA audit cycle for essential entities will include documentation requests for all four components. "We use TLS" is not a policy — it is a protocol choice. A policy specifies which TLS version, which cipher suites, why, reviewed when, and by whom.

What "Where Appropriate, Encryption" Means

The phrase "where appropriate, encryption" is not a carve-out. ENISA guidance and national transpositions consistently interpret this to mean encryption is required wherever:

For SaaS developers, this covers transport encryption (TLS), database encryption at rest, secrets management, and backup encryption — all of which must be addressed in the written policy.


2. ENISA Algorithm Selection: Approved and Prohibited

ENISA publishes annual cryptographic algorithm recommendations. The 2024 ENISA Recommendations on Cryptographic Algorithms are the reference document for Art.21(2)(h) compliance. NCAs will compare your policy against this list.

Transport Encryption

Required:

Prohibited:

TLS 1.3 Cipher Suites (all mandatory-safe):

TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256

TLS 1.2 Permitted Cipher Suites (restricted list):

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Prohibited TLS 1.2 Cipher Suites:

TLS_RSA_*                    # no forward secrecy
TLS_*_CBC_*                  # BEAST/LUCKY13/POODLE-CBC exposure
TLS_*_RC4_*                  # RC4 broken
TLS_*_3DES_*                 # SWEET32 attack
TLS_*_EXPORT_*               # export-grade (Logjam)
TLS_*_NULL_*                 # no encryption
TLS_*_anon_*                 # no authentication

Symmetric Encryption (Data at Rest)

AlgorithmKey LengthStatusUse Case
AES-GCM256-bitRecommendedDatabase encryption, file encryption
AES-CBC256-bitAcceptable (authenticated)Legacy systems only
AES-CBC128-bitAcceptable (authenticated)Legacy, plan migration
3DESanyProhibitedNo new use
DESanyProhibitedNo use
RC4anyProhibitedNo use
ChaCha20-Poly1305256-bitRecommendedMobile, embedded

Critical rule: AES-CBC must always be combined with an HMAC-SHA256 or HMAC-SHA384 MAC. Using CBC without authentication creates padding oracle vulnerabilities. AES-GCM provides integrated authentication — prefer it for all new implementations.

Asymmetric Encryption and Key Exchange

AlgorithmParametersStatus
RSA≥ 3072-bitRecommended (≥ 4096 preferred)
RSA2048-bitAcceptable until 2030
RSA≤ 1024-bitProhibited
ECDSA / ECDHP-256 (secp256r1)Recommended
ECDSA / ECDHP-384 (secp384r1)Recommended
ECDSA / ECDHP-521Acceptable
EdDSAEd25519Recommended
EdDSAEd448Recommended
DH≥ 3072-bitAcceptable
DH≤ 1024-bitProhibited

Hash Functions

AlgorithmStatusUse Case
SHA-256RecommendedSignatures, HMAC
SHA-384RecommendedHigher-security contexts
SHA-512RecommendedHigh-security contexts
SHA-3 familyRecommendedFuture-proof, post-quantum adjacent
SHA-1Prohibited (signatures), Deprecated (HMAC)No new use in signatures
MD5ProhibitedNo use

3. nginx TLS Hardening Configuration

A compliant nginx configuration for TLS 1.3 + restricted TLS 1.2:

# /etc/nginx/conf.d/tls-hardening.conf
# NIS2 Art.21(2)(h) compliant TLS configuration
# Last reviewed: 2026-04-16
# Owner: Platform Engineering
# Reference: ENISA Cryptographic Algorithm Recommendations 2024

ssl_protocols TLSv1.2 TLSv1.3;

# TLS 1.3: cipher suites are non-negotiable (set by OpenSSL)
# TLS 1.2: restrict to ECDHE + AESGCM/CHACHA (no CBC, no RSA key exchange)
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;

# ECDH curve selection (P-256 primary, P-384 secondary)
ssl_ecdh_curve X25519:prime256v1:secp384r1;

# Session management (no session tickets for perfect forward secrecy preservation)
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

# HSTS (2-year max-age, include subdomains)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# Certificate chain
ssl_certificate /etc/ssl/certs/your-domain.crt;
ssl_certificate_key /etc/ssl/private/your-domain.key;
ssl_trusted_certificate /etc/ssl/certs/chain.crt;

# DH params (4096-bit for TLS 1.2 DHE fallback)
# Generate: openssl dhparam -out /etc/ssl/dhparam.pem 4096
ssl_dhparam /etc/ssl/dhparam.pem;

NCA Audit Note: Keep a dated configuration changelog. Auditors will ask when you last reviewed your TLS configuration and who approved changes.


4. Caddy TLS Hardening Configuration

Caddy's automatic HTTPS handles certificate renewal but requires explicit cipher restrictions for Art.21(2)(h) compliance:

# Caddyfile — NIS2 Art.21(2)(h) compliant
# Last reviewed: 2026-04-16
# Owner: Platform Engineering

{
  # Global TLS policy
  servers {
    protocols tls1.2 tls1.3
    
    # Restrict TLS 1.2 cipher suites
    # Caddy (via Go crypto/tls) defaults are already ECDHE-based
    # Explicit restriction for audit trail
  }
}

your-domain.com {
  tls {
    protocols tls1.2 tls1.3
    
    # Curves: X25519 preferred (highest performance + security)
    curves x25519 p256 p384
    
    # Cipher suites (Go crypto/tls identifiers)
    ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
  }
  
  header {
    Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "DENY"
  }
}

Verification command (document in audit evidence):

# Test TLS configuration against ENISA requirements
# Run and save output dated for NCA evidence package
testssl.sh --protocols --ciphers --headers \
  --severity HIGH --html your-domain.com \
  | tee /var/log/tls-audit-$(date +%Y-%m-%d).html

5. Key Management Policy Template

Art.21(2)(h) requires a key management policy. This template covers the minimum NCA-auditable elements:

CRYPTOGRAPHIC KEY MANAGEMENT POLICY
Version: 1.0
Effective Date: [DATE]
Owner: [CISO / CTO]
Review Frequency: Annual (or after cryptographic incident)
Reference: NIS2 Art.21(2)(h), ENISA Cryptographic Recommendations 2024

1. SCOPE
   Applies to all cryptographic keys used in production systems:
   - TLS/HTTPS certificates and private keys
   - Database encryption keys (at-rest encryption)
   - API signing keys and JWT secrets
   - SSH keys for infrastructure access
   - Backup encryption keys
   - Code signing keys

2. KEY GENERATION
   - All keys generated using cryptographically secure random sources
     (CSPRNG: /dev/urandom, HSM, cloud KMS hardware randomness)
   - Minimum key lengths per ENISA 2024 recommendations:
     RSA ≥ 3072-bit, ECDSA P-256/P-384, symmetric AES-256
   - Keys never generated in untrusted environments

3. KEY STORAGE
   - Private keys stored in Hardware Security Modules (HSMs) or
     Cloud KMS (AWS KMS, GCP Cloud KMS, Azure Key Vault) where feasible
   - Keys never stored in source code, config files, or version control
   - Secrets management: HashiCorp Vault / cloud-native secrets manager
   - Database encryption keys separated from data they protect

4. KEY ROTATION SCHEDULE
   | Key Type              | Rotation Frequency | Trigger Conditions              |
   |-----------------------|--------------------|--------------------------------|
   | TLS certificates      | Before expiry (-30d)| Compromise, CA revocation      |
   | API signing keys      | 90 days            | Personnel change, compromise   |
   | JWT secrets           | 90 days            | Compromise suspected           |
   | Database master keys  | Annual             | Staff turnover, audit finding  |
   | SSH infrastructure    | 90 days            | Staff departure, compromise    |
   | Backup encryption     | Annual             | Compromise, key material age   |

5. KEY DISTRIBUTION
   - Keys transmitted only over encrypted channels (TLS 1.3)
   - No key material transmitted via email, Slack, or unencrypted chat
   - Key sharing requires documented approval and audit log

6. KEY REVOCATION AND DESTRUCTION
   - Compromised keys revoked within 4 hours of confirmed compromise
   - Certificate revocation via OCSP/CRL within same timeframe
   - Key destruction: NIST SP 800-88 Rev.1 (cryptographic erasure or physical)
   - Destruction documented with date, method, and authorising personnel

7. CRYPTOGRAPHIC AGILITY
   - Technology register maintained listing all cryptographic algorithms in use
   - Annual review against ENISA recommendations for deprecated algorithms
   - Post-quantum migration assessment: see Section 8

8. POST-QUANTUM PREPAREDNESS
   - Current inventory: [list algorithms in use]
   - NIST PQC candidates adopted: [e.g., ML-KEM for key encapsulation]
   - Migration target date: 2027-2030 (per ENISA PQC timeline)
   - Hybrid classical/PQC deployment: [date planned]

9. INCIDENT RESPONSE
   - Cryptographic key compromise triggers NIS2 Art.23 incident assessment
   - Key compromise affecting personal data also triggers GDPR Art.33 72h notification
   - Incident log includes: key type, estimated exposure window, affected systems

10. AUDIT AND REVIEW
    - Annual third-party review of key management practices
    - NCA audit evidence: this policy + key rotation logs + HSM/KMS audit logs
    - Last reviewed: [DATE] | Reviewed by: [NAME, ROLE] | Next review: [DATE]

6. Post-Quantum Cryptography: NIST PQC and EU Timeline

Art.21(2)(h) includes an implicit forward-looking obligation — ENISA guidance identifies post-quantum cryptography (PQC) migration as a required element of a complete cryptography policy. NCAs performing June 2026 audits will not require PQC deployment, but will expect a documented assessment and migration roadmap.

NIST PQC Finalized Standards (August 2024)

NIST published three post-quantum cryptographic standards in August 2024:

StandardAlgorithmTypeUse Case
FIPS 203ML-KEM (Kyber)Key Encapsulation MechanismTLS key exchange, encrypted sessions
FIPS 204ML-DSA (Dilithium)Digital SignatureCode signing, certificates
FIPS 205SLH-DSA (SPHINCS+)Digital SignatureAlternative signature scheme

A fourth standard, FN-DSA (FALCON), is forthcoming in 2025.

The EU Timeline

MilestoneDateImplication
ENISA PQC Recommendations published2024-11Policy framework for EU entities
BSI PQC Migration Guidelines2025German essential entities: document PQC roadmap
ETSI quantum-safe TLS profile2025-2026TLS PQC cipher suite standards
EU financial sector PQC transition2028-2030EBA/ESMA guidance expected
ENISA target: critical infra PQC deployment2030Long-lead systems (ICS/SCADA)

Hybrid TLS 1.3 with ML-KEM (Implementation Preview)

Current browser and server support uses hybrid key exchange (classical ECDH + ML-KEM):

# Python 3.12+ with liboqs (Open Quantum Safe)
# Preview implementation — not yet production-ready for all stacks
# Document as "assessed, monitoring IETF/NIST standardization"

from oqs import KeyEncapsulation

def demonstrate_ml_kem_768():
    """
    ML-KEM-768 (FIPS 203) key encapsulation demonstration.
    Hybrid deployment: use alongside ECDH P-256 until PQC-only is safe.
    """
    # Server: generate key pair
    with KeyEncapsulation('ML-KEM-768') as server_kem:
        public_key = server_kem.generate_keypair()
        
        # Client: encapsulate shared secret
        with KeyEncapsulation('ML-KEM-768') as client_kem:
            ciphertext, shared_secret_client = client_kem.encap_secret(public_key)
        
        # Server: decapsulate
        shared_secret_server = server_kem.decap_secret(ciphertext)
        
        assert shared_secret_client == shared_secret_server
        return shared_secret_server  # 32-byte shared secret

# For NCA audit evidence: document that PQC assessment is complete,
# hybrid deployment is planned for Q3 2027, monitoring IETF TLS PQC extensions.

What to Document for the June 2026 Audit

NCAs will accept a documented roadmap rather than deployed PQC. Your policy should state:

  1. Current inventory: List all asymmetric algorithms currently in production
  2. Threat assessment: "Harvest Now, Decrypt Later" attack window for your data sensitivity
  3. Migration target: Specific date for hybrid PQC deployment (e.g., "Q4 2027: TLS ML-KEM hybrid")
  4. Monitoring commitment: How you track IETF PQC TLS extensions, ENISA updates

7. Python NIS2CryptoPolicyAssessor

"""
NIS2CryptoPolicyAssessor — Art.21(2)(h) compliance assessment tool.
Assesses cryptographic policy coverage against ENISA 2024 recommendations.
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
from datetime import date

class ComplianceStatus(Enum):
    COMPLIANT = "compliant"
    PARTIAL = "partial"
    NON_COMPLIANT = "non_compliant"
    UNKNOWN = "unknown"

class AlgorithmStatus(Enum):
    APPROVED = "approved"
    ACCEPTABLE = "acceptable"
    DEPRECATED = "deprecated"
    PROHIBITED = "prohibited"

@dataclass
class AlgorithmAssessment:
    algorithm: str
    key_length: Optional[str]
    status: AlgorithmStatus
    enisa_reference: str
    migration_required_by: Optional[date] = None
    replacement: Optional[str] = None

@dataclass
class KeyManagementAssessment:
    has_written_policy: bool
    has_rotation_schedule: bool
    uses_hsm_or_kms: bool
    has_destruction_procedure: bool
    last_review_date: Optional[date]
    
    def status(self) -> ComplianceStatus:
        score = sum([
            self.has_written_policy,
            self.has_rotation_schedule,
            self.uses_hsm_or_kms,
            self.has_destruction_procedure,
            self.last_review_date is not None and 
            (date.today() - self.last_review_date).days <= 365
        ])
        if score >= 5: return ComplianceStatus.COMPLIANT
        if score >= 3: return ComplianceStatus.PARTIAL
        return ComplianceStatus.NON_COMPLIANT

@dataclass
class NIS2CryptoAssessment:
    entity_name: str
    assessment_date: date
    tls_min_version: str
    prohibited_protocols_disabled: bool
    algorithm_inventory: list[AlgorithmAssessment] = field(default_factory=list)
    key_management: Optional[KeyManagementAssessment] = None
    has_pqc_assessment: bool = False
    has_pqc_roadmap: bool = False
    certificate_auto_renewal: bool = False
    has_crypto_incident_procedure: bool = False
    notes: list[str] = field(default_factory=list)

class NIS2CryptoPolicyAssessor:
    """
    Assesses NIS2 Art.21(2)(h) cryptography policy compliance.
    Use output as evidence package for NCA audit preparation.
    """
    
    PROHIBITED_ALGORITHMS = {
        "ssl2.0", "ssl3.0", "tls1.0", "tls1.1",
        "des", "3des", "rc4", "rc2", "md5", "sha1_signatures",
        "rsa_1024", "rsa_512", "dh_1024"
    }
    
    def assess(self, assessment: NIS2CryptoAssessment) -> dict:
        findings = []
        gaps = []
        
        # TLS version check
        if assessment.tls_min_version not in ("tls1.2", "tls1.3"):
            gaps.append({
                "control": "TLS minimum version",
                "gap": f"Minimum TLS version '{assessment.tls_min_version}' does not meet NIS2 Art.21(2)(h). Require TLS 1.2 minimum.",
                "severity": "critical",
                "remediation": "Disable TLS 1.1 and below in all reverse proxies and load balancers."
            })
        else:
            findings.append("TLS minimum version: COMPLIANT")
        
        # Prohibited protocols
        if not assessment.prohibited_protocols_disabled:
            gaps.append({
                "control": "Prohibited protocol enforcement",
                "gap": "SSL/TLS 1.0/1.1 not confirmed disabled. NCA auditors will perform testssl.sh scan.",
                "severity": "critical",
                "remediation": "Run testssl.sh and document results. Disable deprecated protocols in nginx/Caddy/HAProxy."
            })
        
        # Algorithm inventory
        prohibited_found = [
            a for a in assessment.algorithm_inventory 
            if a.status == AlgorithmStatus.PROHIBITED
        ]
        if prohibited_found:
            for algo in prohibited_found:
                gaps.append({
                    "control": f"Prohibited algorithm: {algo.algorithm}",
                    "gap": f"Prohibited algorithm {algo.algorithm} detected. ENISA: {algo.enisa_reference}",
                    "severity": "critical",
                    "remediation": f"Migrate to {algo.replacement or 'ENISA-approved alternative'} immediately."
                })
        
        # Key management
        if assessment.key_management is None:
            gaps.append({
                "control": "Key management policy",
                "gap": "No key management assessment provided. Art.21(2)(h) requires documented key lifecycle procedures.",
                "severity": "high",
                "remediation": "Complete key management policy using the NIS2 Art.21(2)(h) template."
            })
        else:
            km_status = assessment.key_management.status()
            if km_status == ComplianceStatus.NON_COMPLIANT:
                gaps.append({
                    "control": "Key management lifecycle",
                    "gap": "Key management practices insufficient for Art.21(2)(h).",
                    "severity": "high",
                    "remediation": "Implement: written policy, rotation schedule, HSM/KMS, destruction procedure."
                })
            elif km_status == ComplianceStatus.PARTIAL:
                gaps.append({
                    "control": "Key management lifecycle",
                    "gap": "Key management partially compliant. Review missing elements.",
                    "severity": "medium",
                    "remediation": "Address: " + ", ".join([
                        "written policy" if not assessment.key_management.has_written_policy else "",
                        "rotation schedule" if not assessment.key_management.has_rotation_schedule else "",
                        "HSM/KMS" if not assessment.key_management.uses_hsm_or_kms else "",
                        "destruction procedure" if not assessment.key_management.has_destruction_procedure else "",
                    ]).strip(", ")
                })
            else:
                findings.append("Key management lifecycle: COMPLIANT")
        
        # Post-quantum
        if not assessment.has_pqc_assessment:
            gaps.append({
                "control": "Post-quantum cryptography assessment",
                "gap": "No PQC assessment documented. ENISA recommends all essential entities document PQC migration plans.",
                "severity": "medium",
                "remediation": "Document current algorithm inventory + 'Harvest Now Decrypt Later' risk + migration roadmap."
            })
        
        # Certificate renewal
        if not assessment.certificate_auto_renewal:
            gaps.append({
                "control": "Certificate lifecycle automation",
                "gap": "No automated certificate renewal. Manual renewal creates expiry risk.",
                "severity": "medium",
                "remediation": "Implement ACME automation (certbot, Caddy automatic TLS, cert-manager in Kubernetes)."
            })
        
        # Crypto incident procedure
        if not assessment.has_crypto_incident_procedure:
            gaps.append({
                "control": "Cryptographic incident response",
                "gap": "No documented procedure for key compromise response. NIS2 Art.23 may be triggered by key compromise.",
                "severity": "medium",
                "remediation": "Add cryptographic incident procedure to incident response runbook."
            })
        
        # Score
        total_controls = 6
        critical_gaps = len([g for g in gaps if g["severity"] == "critical"])
        high_gaps = len([g for g in gaps if g["severity"] == "high"])
        compliant_controls = total_controls - len(gaps)
        
        overall = ComplianceStatus.NON_COMPLIANT
        if critical_gaps == 0 and high_gaps == 0 and len(gaps) <= 1:
            overall = ComplianceStatus.COMPLIANT
        elif critical_gaps == 0:
            overall = ComplianceStatus.PARTIAL
        
        return {
            "entity": assessment.entity_name,
            "assessment_date": str(assessment.assessment_date),
            "article": "NIS2 Art.21(2)(h)",
            "overall_status": overall.value,
            "compliant_controls": compliant_controls,
            "total_controls": total_controls,
            "critical_gaps": critical_gaps,
            "findings": findings,
            "gaps": gaps,
            "nca_audit_readiness": "READY" if overall == ComplianceStatus.COMPLIANT else "NOT READY",
            "priority_actions": [g["remediation"] for g in gaps if g["severity"] == "critical"]
        }

8. The 25-Item NIS2 Art.21(2)(h) Developer Checklist

Use this list to prepare your NCA audit evidence package. Each item must be documented with evidence (config file, policy document, tool output, or dated review record).

Transport Encryption (TLS)

Encryption at Rest

Key Management

Policy and Documentation

Post-Quantum Readiness

Incident Response


9. NCA Audit Documentation Package

When preparing for a June 2026 NCA audit, assemble the following as your Art.21(2)(h) evidence package:

Document 1: Cryptography Policy

Document 2: Algorithm Inventory

Document 3: TLS Configuration Evidence

Document 4: Key Management Audit Trail

Document 5: Post-Quantum Assessment


10. Intersection with Other NIS2 and EU Regulations

Art.21(2)(h) does not exist in isolation. Cryptography requirements intersect with:

GDPR Art.32: Security of Processing

GDPR Art.32(1)(a) explicitly mentions "the pseudonymisation and encryption of personal data" as appropriate technical measures. For SaaS entities subject to both NIS2 and GDPR, Art.21(2)(h) and Art.32 are complementary — a single cryptography policy can satisfy both. Document the dual-compliance mapping.

NIS2 Art.21(2)(j): Multi-Factor Authentication

MFA implementations using hardware tokens (FIDO2/WebAuthn) rely on asymmetric cryptography (ECDSA on P-256). Your Art.21(2)(h) algorithm selection policy must cover the cryptographic primitives used in your authentication stack.

NIS2 Art.23: Incident Reporting

A key compromise that affects the confidentiality or integrity of your systems may trigger NIS2 Art.23 incident reporting. Your cryptographic incident response procedure (Checklist Item 25) should include an Art.23 trigger assessment.

CRA Art.14: Vulnerability Reporting (September 2026)

Software manufacturers under the Cyber Resilience Act must report actively exploited vulnerabilities within 24 hours to ENISA from September 2026. Cryptographic vulnerabilities in your product (broken cipher, weak key generation) that are actively exploited qualify. Your CRA compliance must include cryptographic vulnerability handling within the same framework as your NIS2 Art.21(2)(h) CVD policy.

Cloud Jurisdiction and Cryptography Sovereignty

For essential entities using US-headquartered cloud providers, CLOUD Act jurisdiction risk applies to encrypted data: if a US provider holds key material (KMS), US law enforcement can compel access regardless of data location. Art.21(2)(h) supply chain risk assessment (linked to Art.21(2)(d)) should document whether your encryption architecture is cloud-act-resilient — i.e., whether your key material is under EU jurisdiction. EU-native infrastructure where the provider has no US parent eliminates this exposure.


Conclusion

NIS2 Art.21(2)(h) transforms cryptographic best practices into regulatory obligations. For essential and important entities, a documented cryptography policy covering algorithm selection, key management lifecycle, certificate automation, and post-quantum preparedness is now auditable from June 2026.

The technical controls — TLS 1.3 with restricted cipher suites, AES-256-GCM for data at rest, proper key rotation, HSM or KMS storage — are achievable by any SaaS team. The gap is almost always documentation: written policies, dated reviews, and the audit trail that demonstrates these controls are consistently applied.

Start with the 25-item checklist and the key management policy template. Run testssl.sh against your endpoints and save the dated output. Document your PQC assessment even if migration is years away. This evidence package is what NCA auditors will request — and what separates compliant entities from those facing Art.32 enforcement.

EU-native infrastructure like sota.io — where key material stays under EU jurisdiction and there is no US parent subject to CLOUD Act compelled disclosure — directly addresses the supply chain cryptography risk that Art.21(2)(d) and Art.21(2)(h) jointly create for essential entities using US-headquartered cloud providers.

See also: