π PCL - Policy-based Certificate Linter

A flexible X.509 certificate linter that validates certificates against configurable YAML-based policies. Ensure compliance with RFC 5280, organizational standards, or industry best practices.
π Quick Start
go install github.com/cavoq/PCL/cmd/pcl@latest
pcl --policy <path> --cert <path> [--crl <path>] [--ocsp <path>] [--output text|json|yaml]
By default, only failed rules are shown. Use -v to include passed rules and -vv to include skipped rules.
You can also fetch a TLS certificate chain from HTTPS URLs:
pcl --policy <path> --cert-url https://example.test --cert-url-timeout 10s --cert-url-save-dir ./downloads
π Policy Configuration
Policies are YAML files defining validation rules with a simple declarative syntax.
id: rfc5280
rules:
- id: version-v3
target: certificate.version
operator: eq
operands: [3]
severity: error
- id: signature-algorithm-secure
target: certificate.signatureAlgorithm.algorithm
operator: in
operands:
- SHA256-RSA
- SHA384-RSA
- ECDSA-SHA256
severity: error
# Conditional rule using "when" clause
- id: rsa-key-size-minimum
when:
target: certificate.subjectPublicKeyInfo.algorithm
operator: eq
operands: [RSA]
target: certificate.subjectPublicKeyInfo.publicKey.keySize
operator: gte
operands: [2048]
severity: error
- id: ca-basic-constraints
target: certificate.basicConstraints.cA
operator: eq
operands: [true]
severity: error
appliesTo: [root, intermediate]
# Optional document reference (used by text output)
- id: key-usage-leaf
reference: RFC5280 4.2.1.3
target: certificate.keyUsage
operator: keyUsageLeaf
severity: error
ποΈ Supported Policies
- RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
β Supported Operators
Comparison Operators
| Operator |
Description |
eq |
Equality check |
neq |
Not equal check |
gt, gte |
Greater than (or equal) |
lt, lte |
Less than (or equal) |
in |
Value in allowed list |
notIn |
Value not in disallowed list |
contains |
String/array contains value |
matches |
Compare two field paths for equality |
Presence & Value Operators
| Operator |
Description |
present |
Field existence check |
absent |
Field does not exist |
isEmpty, notEmpty |
Value emptiness check |
positive |
Value is a positive number |
odd |
Value is an odd number (for RSA exponent validation) |
maxLength, minLength |
String/array length constraints |
regex, notRegex |
Regular expression pattern matching |
Date Operators
| Operator |
Description |
before |
Date is before current time |
after |
Date is after current time |
validityOrderCorrect |
Validates notBefore < notAfter |
validityDays |
Certificate validity period check |
Extension Operators
| Operator |
Description |
isCritical, notCritical |
Extension criticality check |
noUnknownCriticalExtensions |
No unhandled critical extensions |
Certificate Chain Operators
| Operator |
Description |
signatureValid |
Cryptographic signature verification |
signatureAlgorithmMatchesTBS |
Signature algorithm matches TBS certificate |
issuedBy |
Issuer DN matches issuer's subject DN |
akiMatchesSki |
Authority Key ID matches issuer's Subject Key ID |
pathLenValid |
Path length constraint validation |
serialNumberUnique |
Serial number uniqueness in chain |
Key Usage & Constraints Operators
| Operator |
Description |
sanRequiredIfEmptySubject |
SAN required when subject is empty |
keyUsageCA, keyUsageLeaf |
Key usage validation by cert type |
ekuContains, ekuNotContains |
Extended key usage checks |
ekuServerAuth, ekuClientAuth |
TLS authentication EKU checks |
noUniqueIdentifiers |
Absence of issuer/subject unique IDs |
CRL Operators
| Operator |
Description |
crlValid |
CRL is within thisUpdate/nextUpdate window |
crlNotExpired |
CRL nextUpdate is in the future |
crlSignedBy |
CRL signature verification against chain |
notRevoked |
Certificate not in CRL revoked list |
OCSP Operators
| Operator |
Description |
ocspValid |
OCSP response is within validity window and signature is valid |
notRevokedOCSP |
Certificate not revoked according to OCSP |
ocspGood |
Certificate has explicit Good status in OCSP response |
Path Validation Operators
| Operator |
Description |
nameConstraintsValid |
Validates names against permitted/excluded subtrees from chain |
certificatePolicyValid |
Validates policy OIDs through chain with mappings and constraints |
π Conditional Rules
Rules can include a when clause to apply only when certain conditions are met:
- id: rsa-exponent-valid
when:
target: certificate.subjectPublicKeyInfo.algorithm
operator: eq
operands: [RSA]
target: certificate.subjectPublicKeyInfo.publicKey.exponent
operator: odd
severity: error
This rule only validates RSA exponent when the certificate uses RSA. If the condition is not met, the rule is skipped.
Certificate Chain Support
PCL automatically builds and validates certificate chains, applying rules based on certificate position:
leaf: End-entity certificates
intermediate: CA certificates in the chain
root: Self-signed root CA certificates
Use appliesTo in rules to target specific certificate types.
π§ Development
go build -o pcl ./cmd/pcl
go test -v -race ./...
golangci-lint run ./...