Designing a Certificate Profile Format Worth Adopting
Corey Bonnell
In Certificate Profiles Need a Single Source of Truth, I made the argument that the CP/CPS is a second copy of a CA’s certificate profile, written in prose. The Baseline Requirements make that copy normative. And keeping two copies in sync by hand simply does not work.
Recent incidents show this clearly. Microsoft mis-issued more than 75 million valid certificates because an edit to its CPS said keyEncipherment was absent, while issuance kept including it. HARICA did the same thing twice in one month, once on id-kp-clientAuth and once on the AIA OCSP URI. Both times, the document and the issuance system were edited separately. Entrust made a CPS edit meant for its EV profile, but it was made on the OV profile. This typo became a mis-issuance event, and it was later named in Entrust’s distrust announcement.
The common cause is duplication and drift. The fix is one that software engineering settled on long ago: Don’t Repeat Yourself (DRY). Write the profile once, in a machine-readable format, and generate the document, the configuration, and the lints from it. A generated file can be wrong, but it cannot drift, because it has no separate copy to drift from.
Now there is policy behind this idea. Chrome’s draft Quantum-resistant Root Program (CQRP) makes machine-readable profiles a requirement, not an option.
The requirement now has a deadline
The CQRP draft policy, in Section 2.3.2, requires each Merkle Tree Certificate (MTC) CA that issues Subscriber certificates to publish a machine-readable certificate profile.
The policy is clear about what a profile must contain. It must list every field and extension the CA can include. For each one, it must state whether it is required (MUST, MAY, or MUST NOT), whether it is critical, which values are allowed and which encodings are allowed. And, for the fields that can contain multiple elements, the profile must describe the allowed order and count. Anything not listed MUST NOT appear. The policy even suggests generating these profiles automatically from the CA’s live issuance configuration. That is the single-source-of-truth idea, stated in policy.
The requirement is also enforced. Section 2.4.4 makes pre-issuance linting against the profile blocking from September 15, 2027. After that date, a TBSCertificateLogEntry that does not match its profile cannot enter the issuance log. CAs must also publish a mapping that shows, for each profile requirement, which check enforces it, and must clearly mark any requirement that is not enforced.
So the question is no longer whether CAs need a machine-readable profile format. Instead, the question is what that format should look like. The design space in this area is potentially huge, but there are mistakes that must be avoided.
The mistakes a profile format must avoid
I have been designing such a profile description format that drives a validator built on Infrared, the context-aware validation framework I have been building. Most of the design work has been finding the ways a format like this can fail, and avoiding them. Five mistakes stand out.
Bringing back the duplication you meant to remove
The whole point is to have one authoritative copy. If the format cannot share a definition across profiles, it quietly recreates the problem. A policy OID, an extension, or a subject attribute layout used in six profiles gets written six times. Now there are six copies that can drift. A format that fails here has already lost, because it fixes drift by adding more places to drift.
Being a custom format that needs custom tools
A brand-new syntax needs new parsers, new editors, new diff tools, and new validators. Every one of those must be built and maintained before you can check a single certificate. And, it’s a training cost that the CA team must absorb.
Putting logic where it does not belong
It is tempting to make the format handle everything: conditions across fields, path relationships, any constraint at all. This blog post describes the danger: teams slowly rebuild a full programming language inside their configuration format, one feature at a time, and end up worse off than if they had used a standard configuration format and deferred complex logic to application code (other linters, in this case).
Being so general that you must be an ASN.1 expert to use it
A format that allows any ASN.1 document structure and field can express anything, but almost no one can use it. It is verbose, easy to get wrong, and out of reach for the very people who understand the profile best. If saying “this certificate must be a version 3 certificate” requires the author to remember that the version field is explicitly tagged, the format has failed as an authoring tool, no matter how powerful it is. This is the path I first went down, but quickly realized it was incredibly painful to use.
Being permissive by default
If the format allows anything the profile does not mention, then a field the author forgot passes silently. That is the exact failure mode behind the incidents: a certificate contained something tooling did not account for, and nothing caught it. It also goes against the CQRP, which requires that any field or extension not enumerated in the profile must not appear in the certificate. So the default must be the strict one. Every field and extension in the certificate must be defined by the profile, or it is flagged. Allowing something the profile does not describe has to be a deliberate, opt-in choice, never the silent default.
How the Infrared profile format avoids them
Each mistake has a matching design decision to avoid it.
Templates and snippets, so you write once and reuse everywhere
A definition, such as a policy OID, an extension, or a reusable field constraint, is written once and referenced wherever it is needed. If a policy OID is used in six profiles, it is defined in one place and pulled into all six using a label. A change is a single edit in a single place, and the profiles cannot disagree about it, because there is only one copy. This is the DRY rule applied to the profiles themselves, not only to the profile-versus-CPS problem.
JSON5 as the format, so the tools already exist
Instead of inventing a language, the format uses JSON5. JSON5 is JSON with a few practical improvements that make it easy to write by hand and self-document. The most important feature is comments, which matter a lot when a profile is reviewed like code. JSON5 converts cleanly to standard JSON, so the existing tools such as parsers, validators, editors, and diff tools all work already. No one has to build a parser to adopt.
Field value matching and presence operators, but no cross-field logic
The format does what it is good at: matching values, and stating presence with operators like MUST and MUST NOT, for each field and extension. It does not add cross-field constraints and conditional logic. A check that truly needs cross-field reasoning is best written as a separate profile with common elements defined in one place using templates and snippets. The format stays a readable specification, and the general logic stays in the tools made for it.
Hand-built schemas for each supported field, attribute, and extension
This is the decision that makes the rest usable. Instead of exposing raw ASN.1 and asking authors to encode everything, the format includes hand-built schemas for each field, attribute, and extension it supports. An author states that an extension must be present, non-critical, and limited to a given EKU, in plain terms, and the schema handles how that maps to the encoding. You get correct profiles without being an ASN.1 expert, and the authoring matches how CA staff already think about their profiles.
Closed by default, so nothing passes unless the profile describes it
The profile must account for every field and extension the certificate contains. Anything the profile does not describe is flagged as a finding. The CQRP requires this outcome for certificates: any field or extension not enumerated in the profile must not appear. A closed-by-default format is how you guarantee it. If a CA does want to permit something without fully constraining it, that has to be stated explicitly in the profile. Permissive handling is opt-in, and strictness is what you get when you say nothing. A field the author forgot fails the check instead of slipping through.
Tying the format into Infrared’s validators
The format is one part, and the validator that consumes the profile format and validates against real certificates is the other part. The validator I am building on Infrared reads a profile file and checks certificates against it. It runs in addition to the standard well-formedness checks that verify compliance against the standards. Infrared has its own CA/Browser Forum TLS validator (which powers the MTC TBSCertificateLogEntry validator) for those shared-standard checks, and the profile validator sits right alongside it. The shared standards are being checked, and Infrared’s profile validator adds the CA-specific requirements that no shared linter has ever had access to, in the same pre-issuance step. A mismatch between a certificate and the CA’s own profile becomes a pre-issuance failure, instead of a Bugzilla bug and a five-day revocation clock. That is exactly the outcome the CQRP now requires for MTC issuance.
The goal is not a format for its own sake. It is a profile your team can actually author. It can generate your CPS language and lints from one source. And it fails a mismatch before issuance, not after. If you want that for your CA, whether to meet the CQRP requirement or to stop trusting hand-kept certificate profiles in your CPS, reach out.