Skip to content
Open
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
6 changes: 4 additions & 2 deletions test-tools/ossl_test_tools/crltest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@

from pathlib import Path

from . import alt_ta, indirect, no_chain
from . import alt_ta, delta, indirect, no_chain


def _all_cmd(args):
indirect.build(args.source)
alt_ta.build(args.source)
no_chain.build(args.source)
delta.build(args.source)
print(f"regenerated all indirect-CRL artifacts in {args.source}")


Expand All @@ -34,7 +35,8 @@ def register(subparsers):
indirect.register(sub)
alt_ta.register(sub)
no_chain.register(sub)
delta.register(sub)

p = sub.add_parser("all", help="Run indirect, alt-ta, and no-chain in order.")
p = sub.add_parser("all", help="Run indirect, alt-ta, no-chain, and delta in order.")
p.add_argument("--source", type=Path, required=True, help="Path to crltest.c")
p.set_defaults(func=_all_cmd)
103 changes: 103 additions & 0 deletions test-tools/ossl_test_tools/crltest/delta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html

"""Delta-CRL artifacts for the X509_V_FLAG_USE_DELTAS path.

kCrlDeltaBase full CRL signed by kRoot, no revocations, carries a
Freshest CRL extension so EXFLAG_FRESHEST is set and
get_delta_sk() looks for a delta
kCrlDeltaValid delta CRL (deltaCRLIndicator -> base crlNumber) that
revokes kLeaf, valid time window around kVerify

Both CRLs are issued and signed by kRoot and share an identical
AuthorityKeyIdentifier (and no IDP), so check_delta_base() pairs the delta
with the base. kRoot, kRootPrivateKey and kLeaf are read out of the source
file by name; no new certificates are generated.

The time window matches the indirect suite (CRL_LAST_UPDATE/CRL_NEXT_UPDATE)
so kVerify falls inside it: this exercises the happy path where the delta is
current. The expired-delta regression case is intentionally not generated
here.
"""

import datetime
from pathlib import Path

from cryptography import x509
from cryptography.hazmat.primitives import hashes

from .. import cert_util
from ._shared import CRL_LAST_UPDATE, CRL_NEXT_UPDATE, UTC

BASE_CRL_NUMBER = 0x1000
DELTA_CRL_NUMBER = 0x1001
REVOCATION_DATE = datetime.datetime(2026, 3, 20, 0, 0, 0, tzinfo=UTC)


def build(source_path):
root_cert = cert_util.cert_from_c(source_path, "kRoot")
root_key = cert_util.key_from_c(source_path, "kRootPrivateKey")
leaf_cert = cert_util.cert_from_c(source_path, "kLeaf")
akid = cert_util.akid_from_cert(root_cert)

base_crl = (
x509.CertificateRevocationListBuilder()
.issuer_name(root_cert.subject)
.last_update(CRL_LAST_UPDATE)
.next_update(CRL_NEXT_UPDATE)
.add_extension(akid, critical=False)
.add_extension(x509.CRLNumber(BASE_CRL_NUMBER), critical=False)
.add_extension(
x509.FreshestCRL([
x509.DistributionPoint(
full_name=[x509.UniformResourceIdentifier(
"http://crl.example.com/delta.crl"
)],
relative_name=None,
reasons=None,
crl_issuer=None,
),
]),
critical=False)
.sign(private_key=root_key, algorithm=hashes.SHA256())
)

revoked = (
x509.RevokedCertificateBuilder()
.serial_number(leaf_cert.serial_number)
.revocation_date(REVOCATION_DATE)
.build()
)
delta_crl = (
x509.CertificateRevocationListBuilder()
.issuer_name(root_cert.subject)
.last_update(CRL_LAST_UPDATE)
.next_update(CRL_NEXT_UPDATE)
.add_revoked_certificate(revoked)
.add_extension(akid, critical=False)
.add_extension(x509.CRLNumber(DELTA_CRL_NUMBER), critical=False)
.add_extension(x509.DeltaCRLIndicator(BASE_CRL_NUMBER), critical=True)
.sign(private_key=root_key, algorithm=hashes.SHA256())
)

cert_util.update_crl_in_c(source_path, "kCrlDeltaBase", base_crl)
cert_util.update_crl_in_c(source_path, "kCrlDeltaValid", delta_crl)


def _cmd(args):
build(args.source)
print(f"updated kCrlDeltaBase kCrlDeltaValid in {args.source}")


def register(sub):
p = sub.add_parser(
"delta",
help="Regenerate the delta-CRL artifacts (base + valid delta) for the "
"USE_DELTAS path.",
)
p.add_argument("--source", type=Path, required=True, help="Path to crltest.c")
p.set_defaults(func=_cmd)