~~NOTOC~~
====== Scenario 5.4: Policy Validation ======
**Category:** [[.:start|Validation & Trust]] \\
**Complexity:** **** (High) \\
**Prerequisites:** Certificate chain with policy extensions \\
**Estimated Time:** 15-20 minutes
----
===== Description =====
This scenario describes **validation of Certificate Policies** according to RFC 5280. Policy validation ensures that certificates meet organizational requirements:
* **Certificate Policies** (OID 2.5.29.32) - Which policies apply?
* **Policy Mappings** (OID 2.5.29.33) - Policy translations between CAs
* **Policy Constraints** (OID 2.5.29.36) - Restrictions on policy inheritance
* **Inhibit anyPolicy** (OID 2.5.29.54) - Disable anyPolicy
----
===== Workflow =====
flowchart TD
CHAIN[Certificate chain] --> EXTRACT[Extract policies]
EXTRACT --> MAP[Apply policy mappings]
MAP --> INHERIT[Check policy inheritance]
INHERIT --> CONSTRAINT[Check constraints]
CONSTRAINT --> ANY{anyPolicy allowed?}
ANY -->|Yes| MATCH[Check policy match]
ANY -->|No| EXPLICIT[Explicit policy required]
MATCH --> OK{Policy satisfied?}
EXPLICIT --> OK
OK -->|Yes| VALID[Policy valid]
OK -->|No| INVALID[Policy violated]
style VALID fill:#e8f5e9
style INVALID fill:#ffebee
----
===== Code Example (C#) =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography.X509Certificates;
using var ctx = PqCryptoContext.Initialize();
// Load certificates
var serverCert = ctx.LoadCertificate("server.crt.pem");
var intermediate = ctx.LoadCertificate("intermediate-ca.crt.pem");
var root = ctx.LoadCertificate("root-ca.crt.pem");
// Define required policy
var requiredPolicy = new Oid("1.3.6.1.4.1.99999.1.1"); // Example OID
// Chain with policy check
var chain = new X509Chain();
chain.ChainPolicy.ExtraStore.Add(intermediate);
chain.ChainPolicy.ExtraStore.Add(root);
// Add certificate policies
chain.ChainPolicy.CertificatePolicy.Add(requiredPolicy);
// Build and validate chain
bool isValid = chain.Build(serverCert);
// Check for policy errors
var policyErrors = chain.ChainElements
.SelectMany(e => e.ChainElementStatus)
.Where(s => s.Status == X509ChainStatusFlags.InvalidPolicyConstraints ||
s.Status == X509ChainStatusFlags.NoIssuanceChainPolicy)
.ToList();
if (policyErrors.Any())
{
Console.WriteLine("Policy validation failed:");
foreach (var error in policyErrors)
{
Console.WriteLine($" {error.StatusInformation}");
}
}
else
{
Console.WriteLine("Policy validation successful");
}
----
===== Extract Policies from Certificate =====
public class PolicyExtractor
{
public List ExtractPolicies(X509Certificate2 cert)
{
var policies = new List();
// Certificate Policies Extension (2.5.29.32)
var policyExt = cert.Extensions["2.5.29.32"];
if (policyExt == null) return policies;
// Parse ASN.1
var reader = new AsnReader(policyExt.RawData, AsnEncodingRules.DER);
var sequence = reader.ReadSequence();
while (sequence.HasData)
{
var policyInfo = sequence.ReadSequence();
var policyOid = policyInfo.ReadObjectIdentifier();
var policy = new CertificatePolicy
{
PolicyIdentifier = policyOid
};
// Optional: Policy Qualifiers
if (policyInfo.HasData)
{
var qualifiers = policyInfo.ReadSequence();
while (qualifiers.HasData)
{
var qualifier = qualifiers.ReadSequence();
var qualifierId = qualifier.ReadObjectIdentifier();
// CPS URI (1.3.6.1.5.5.7.2.1)
if (qualifierId == "1.3.6.1.5.5.7.2.1")
{
policy.CpsUri = qualifier.ReadCharacterString(UniversalTagNumber.IA5String);
}
// User Notice (1.3.6.1.5.5.7.2.2)
else if (qualifierId == "1.3.6.1.5.5.7.2.2")
{
policy.UserNotice = ParseUserNotice(qualifier);
}
}
}
policies.Add(policy);
}
return policies;
}
}
----
===== Important Policy OIDs =====
^ OID ^ Name ^ Usage ^
| **2.5.29.32.0** | anyPolicy | All policies allowed |
| **2.16.840.1.101.3.2.1.3.13** | id-fpki-common-policy | US Federal PKI |
| **0.4.0.194121.1.2** | NCP | EU Natural Person |
| **0.4.0.194112.1.2** | QCP | EU Qualified Certificate |
| **2.23.140.1.2.1** | DV-SSL | Domain Validated |
| **2.23.140.1.2.2** | OV-SSL | Organization Validated |
| **2.23.140.1.1** | EV-SSL | Extended Validation |
----
===== Policy Mappings =====
public class PolicyMapper
{
// Extract policy mappings from CA certificate
public Dictionary ExtractMappings(X509Certificate2 caCert)
{
var mappings = new Dictionary();
// Policy Mappings Extension (2.5.29.33)
var mappingExt = caCert.Extensions["2.5.29.33"];
if (mappingExt == null) return mappings;
var reader = new AsnReader(mappingExt.RawData, AsnEncodingRules.DER);
var sequence = reader.ReadSequence();
while (sequence.HasData)
{
var mapping = sequence.ReadSequence();
var issuerPolicy = mapping.ReadObjectIdentifier();
var subjectPolicy = mapping.ReadObjectIdentifier();
mappings[issuerPolicy] = subjectPolicy;
}
return mappings;
}
// Propagate policy through chain
public HashSet PropagatePolicy(
X509Certificate2[] chain,
string requiredPolicy)
{
var validPolicies = new HashSet { requiredPolicy };
// From root to end-entity
for (int i = chain.Length - 1; i > 0; i--)
{
var ca = chain[i];
var mappings = ExtractMappings(ca);
var newPolicies = new HashSet();
foreach (var policy in validPolicies)
{
if (mappings.TryGetValue(policy, out var mapped))
{
newPolicies.Add(mapped);
}
else
{
newPolicies.Add(policy);
}
}
validPolicies = newPolicies;
}
return validPolicies;
}
}
----
===== Industry-Specific Policies =====
^ Industry ^ Policy ^ OID Range ^ Requirements ^
| **eIDAS** | QCP-n, QCP-l | 0.4.0.194112.* | Qualified certificates |
| **PSD2** | PSD2-QWAC | 0.4.0.19495.* | Payment Services |
| **US Federal** | FBCA | 2.16.840.1.101.3.* | Federal Bridge CA |
| **Healthcare DE** | gematik | 1.2.276.0.76.4.* | Telematics Infrastructure |
----
===== Policy-Based Access Control =====
public class PolicyBasedAccess
{
private readonly Dictionary _policyAccessMap = new()
{
["2.23.140.1.1"] = AccessLevel.HighSecurity, // EV
["2.23.140.1.2.2"] = AccessLevel.MediumSecurity, // OV
["2.23.140.1.2.1"] = AccessLevel.LowSecurity, // DV
["2.5.29.32.0"] = AccessLevel.Minimal // anyPolicy
};
public AccessLevel DetermineAccessLevel(X509Certificate2 cert)
{
var policies = new PolicyExtractor().ExtractPolicies(cert);
var highestLevel = AccessLevel.None;
foreach (var policy in policies)
{
if (_policyAccessMap.TryGetValue(policy.PolicyIdentifier, out var level))
{
if (level > highestLevel)
{
highestLevel = level;
}
}
}
return highestLevel;
}
}
public enum AccessLevel
{
None = 0,
Minimal = 1,
LowSecurity = 2,
MediumSecurity = 3,
HighSecurity = 4
}
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Prerequisite** | [[.:chain_validation|5.2 Chain Validation]] | Validate chain |
| **Next Step** | [[.:name_constraints|5.5 Name Constraints]] | Name verification |
| **Related** | [[en:int:pqcrypt:szenarien:pki:certificate_policy_definieren|1.5 Certificate Policy]] | Define policy |
----
<< [[.:revocation_check|<- 5.3 Revocation Check]] | [[.:start|^ Validation Overview]] | [[.:name_constraints|5.5 Name Constraints ->]] >>
{{tag>scenario validation policy x509 rfc5280}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//