Summary
- RFC 6487 forbids
authorityCertIssuerandauthorityCertSerialNumberin the Authority Key Identifier of a conforming RPKI resource certificate, even though the broader PKIX syntax in RFC 5280 defines both fields as optional. - LACNIC’s Barry commit
994a598addedauthorityCertIssuerthrough a GeneralNames parser that requires an array. The next day, Rapport commitb1a59achanged its negative fixture from a scalar string to a one-element array and corrected the expected FORT diagnostic from the serial-number field to the issuer field. - The test sequence has three separate evidentiary gates: Barry must construct the malformed repository, the selected relying party must reject or diagnose it, and the resulting VRP set must be empty. The source shows the sequence; it does not provide a public execution transcript or release-grade result.
- Rapport documents four relying-party selectors, but this test’s exact log assertion applies only to
fort2. For the other selectors, an empty output set may show consequence without naming the cause.
The negative test has a positive burden
The field under examination is small. In an RPKI resource certificate, the Authority Key Identifier links a certificate to the public key of its issuer. RFC 6487 requires the extension in resource certificates except for the self-signed case, makes it non-critical, and prescribes a key identifier derived from the issuer’s public key. It also draws a bright profile boundary: authorityCertIssuer and authorityCertSerialNumber must not be present.
That boundary is stricter than the generic X.509 profile on which RPKI is built. RFC 5280 defines the two fields as optional members of the AuthorityKeyIdentifier sequence and says they travel together when used. RPKI removes that latitude. A validator conformance test therefore has a simple apparent job: create a resource certificate containing authorityCertIssuer, place it in a repository, and show that the relying party does not accept the resulting route-origin payload.
The word “create” carries most of the burden. A negative test is only informative if the prohibited condition actually exists in the object presented to the system under test. If a fixture cannot be parsed by the generator, if the generator silently omits the field, or if repository creation stops before the certificate is emitted, a later absence of validated routes says nothing about validator conformance. The test may be red or green for the wrong reason; it may never have crossed the boundary it claims to test.
This is why the September source changes matter. They are not evidence of a routing incident or a broken production validator. They expose the construction contract beneath a test whose name sounds as if the validator were the only interesting component.
A scalar became a GeneralNames array
Barry is LACNIC’s tool for describing valid or deliberately invalid RPKI repositories. Its input language lets a fixture specify a repository tree and override fields inside certificates and signed objects. In commit 994a598321336baf1767f0fbfb460ed96c29fe4f, authored on 1 September 2026, Barry added support for the Authority Key Identifier’s authorityCertIssuer field.
The implementation connects that field to Barry’s ft_gnames type. The corresponding parse_gnames function accepts a set or array, counts its entries, allocates one GeneralName per entry and parses each entry as an object. If the supplied value is not an array, the parser takes its “expected set/array” error path. Barry’s new functional fixture demonstrates the intended shape with three array members: an email-style rfc822Name, an IP address and a registered identifier.
At the parent revision of the Rapport test, the authorityCertIssuer override was not shaped that way. It was a scalar string: CN=Fake Issuer. The source comparison is enough to establish an interface mismatch between that fixture and Barry’s current GeneralNames parser. It is not enough to claim how an earlier Barry binary behaved, whether the test was executed against that binary, or what output a runner recorded. Those would require a runtime trace or pinned build evidence that the public sources do not provide.
Rapport commit b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c, authored on 2 September, corrects the fixture. The scalar becomes a one-element array containing an rfc822Name whose value is an illustrative mailbox literal. That is a deliberately implausible issuer name in a field the RPKI profile forbids anyway; its purpose is not to model a legitimate identity. Its purpose is to make the forbidden GeneralNames member constructible.
The correction is a useful piece of engineering evidence because it changes the precondition rather than the expected validator policy. RFC 6487 did not change between the two commits. The intended outcome—rejection of the malformed certificate—did not change. What changed was the fixture’s ability to express the forbidden structure using the generator’s actual type system.
The diagnostic named the wrong field
The runner changed too. Before the correction, the script asked FORT’s log for a message saying that the Authority Key Identifier contained authorityCertSerialNumber. Yet the fixture was attempting to add authorityCertIssuer. After b1a59a, the exact log assertion names authorityCertIssuer.
That may look like a typo repair, but it reveals a second evidentiary gate. Construction and diagnosis are independent. Even if Barry emits exactly the malformed certificate intended, a test can still assert the wrong reason for rejection. Conversely, a familiar error string can appear for a different malformed certificate if the fixture is not inspected. A dependable result must bind certificate identity to diagnostic identity.
The corrected run.sh makes the desired order legible. It invokes run_barry, then run_rp, then checks the FORT log for the exact issuer-field diagnostic, and finally calls check_vrps. The order is valuable because each stage should leave a separate receipt:
- Barry completed and emitted a repository whose certificate can be decoded to show
authorityCertIssuerpresent. - The selected relying party completed its validation cycle and rejected the relevant chain or object.
- Where the relying party exposes a stable diagnostic, the test matched a message tied to
authorityCertIssuer. - The output contained no VRP derived from the route object beneath the invalid CA certificate.
The source establishes the intended choreography. It does not establish that those four receipts were produced for commit b1a59a. The captured GitHub surface reports no check runs for the commit, and the repository exposes no tags or releases. None of that proves that maintainers ran no tests privately or locally. It means a reader cannot promote the source correction into a publicly reproducible execution result without additional evidence.
Empty output is a consequence, not a diagnosis
Rapport’s check_vrps helper constructs an expected file from its arguments. In this test the function is called with no arguments, so the expected file is empty. The helper then converts the relying party’s CSV output into a common text form, sorts it and diffs it against that empty file. A successful comparison establishes a narrow consequence: no VRP appeared in the file output for the test repository.
That consequence is necessary. The fixture places a ROA beneath the malformed CA certificate; accepting a route payload from that chain would defeat the point of the negative test. But emptiness does not say why the output is empty. The relying party could reject the prohibited AKI member. It could reject another defect in the generated repository. It could fail to retrieve the repository. The run could select the wrong trust anchor, or the generator might fail before serving the object. The output assertion needs construction and execution evidence around it.
For FORT, this particular test adds the exact log assertion. The check_logfile helper first compares the active RP selector with the selector passed by the test; if they differ, it returns without checking the message. Because the script passes fort2, the diagnostic assertion is FORT-specific.
Rapport’s README at the pinned revision documents four supported selectors: FORT 2, Routinator, rpki-client and RPKI Prover. Each test run targets one. The existence of four adapters should not be mistaken for four equivalent assertions in every test. With another selector, this fixture can still check the empty VRP consequence, but the source does not show a validator-specific assertion that names the prohibited field. That distinction is the difference between a portability matrix and a single result copied across four column headings.
What a portable result should record
A useful conformance dashboard would treat construction, diagnosis and output as different columns rather than compressing them into “pass”. The minimum receipt for this test would include the Barry commit and binary fingerprint; the fixture hash; the generator exit status; a hash of the emitted certificate; a decoded AKI showing the prohibited GeneralNames field; the repository transport used; the relying-party name, version and configuration; the validation exit state; the matched diagnostic, if one is stable; and hashes of both expected and actual VRP sets.
Some validators intentionally avoid promising stable human-readable log text. In that case, a portable test need not invent a common error string. It can record a structured rejection class, a validator-specific diagnostic code, or a carefully bounded “no accepted payload” result, provided the constructed input is independently proven. Uniform evidence does not require identical interfaces; it requires comparable claims about what each interface actually demonstrates.
The receipt should also distinguish a source test from an executed test and an executed test from a released test. A commit can express the right condition without having public automation. A local execution can be valid without defining a maintained compatibility promise. A tagged suite can still lack a published matrix across validator versions. These are maturity stages, not accusations.
LACNIC’s December 2025 introduction described Barry and Rapport as early-stage open-source projects. It said Barry would create valid and invalid repositories and Rapport would feed them to validators and examine outputs; at that point the post described FORT as the supported validator. The later README names four selectors. The responsible reading is chronological: the tools evolved. It would be equally wrong to freeze the project at the blog post or to treat a current adapter list as retroactive proof that every test has always carried equal evidence for every validator.
A small correction with a large lesson
The corrected fixture is only a few lines. Its analytical value lies in the boundary it exposes. RPKI conformance suites sit between two complex systems: an object generator that must be capable of producing invalid structures on purpose, and validators that may reject those structures at different layers and report them differently. A mistake on either side can create a persuasive but meaningless colour on a test dashboard.
For operators selecting or upgrading relying-party software, the practical question is not whether one repository contains a test with the right RFC section in its directory name. It is whether a pinned version produced a documented malformed object, whether the candidate validator processed that exact object, and whether the recorded output supports the conclusion being drawn. Source inspection can prove the intended chain. Only an execution receipt proves that the chain ran.
The strongest defensible conclusion today is therefore modest. Barry’s September change supplies the type machinery for authorityCertIssuer. Rapport’s next-day change reshapes the fixture to that machinery and aligns the FORT diagnostic with the field under test. The suite source now describes a more coherent test. The public evidence captured here does not certify the result for FORT or for the other three relying parties.
Sources
- LACNIC Blog, “Open-Source Projects at LACNIC”: https://blog.lacnic.net/en/open-source-projects-lacnic/
- Barry commit
994a598: https://github.com/LACNIC/barry/commit/994a598321336baf1767f0fbfb460ed96c29fe4f - Barry
field.cat the pinned commit: https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/src/field.c - Barry
ext.cat the pinned commit: https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/src/ext.c - Barry GeneralNames functional fixture: https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/test/functional/tests/gnames.rd
- Rapport correction commit
b1a59a: https://github.com/LACNIC/rapport/commit/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c - Corrected Rapport fixture: https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd
- Corrected Rapport runner: https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/run.sh
- Rapport check helpers and README: https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tools/checks.sh and https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/README.md
- RFC 6487, RPKI Certificate and CRL Profile: https://www.rfc-editor.org/rfc/rfc6487.html
- RFC 5280, Internet X.509 PKI Certificate and CRL Profile: https://www.rfc-editor.org/rfc/rfc5280.html
- Pre-correction Rapport fixture and runner at
69da5fe: https://github.com/LACNIC/rapport/blob/69da5fe98cf09594fc009f4151a84368c08489ba/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd and https://github.com/LACNIC/rapport/blob/69da5fe98cf09594fc009f4151a84368c08489ba/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/run.sh - Files changed by correction commit
b1a59a: https://github.com/LACNIC/rapport/commit/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/checks - Fixture path history on
main: https://github.com/LACNIC/rapport/commits/main/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd - Rapport tags and releases: https://github.com/LACNIC/rapport/tags and https://github.com/LACNIC/rapport/releases
Member Briefing
Deeper Profile Context
Sign in with the right membership level to unlock the full briefing and source notes.
Only for Strategic Circle
Strategic Circle
Open to all readers. Unlock profile briefings after joining and signing in.
Join Strategic CircleOnly for Leadership Alliance
Leadership Alliance
For qualified IP-asset owners and management; sign in to unlock alliance briefings.
Join Leadership Alliance
