Scenario 5.4: Policy Validation

Category: 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:


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<CertificatePolicy> ExtractPolicies(X509Certificate2 cert)
    {
        var policies = new List<CertificatePolicy>();
 
        // 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<string, string> ExtractMappings(X509Certificate2 caCert)
    {
        var mappings = new Dictionary<string, string>();
 
        // 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<string> PropagatePolicy(
        X509Certificate2[] chain,
        string requiredPolicy)
    {
        var validPolicies = new HashSet<string> { 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<string>();
            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<string, AccessLevel> _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
}

Relationship Scenario Description
Prerequisite 5.2 Chain Validation Validate chain
Next Step 5.5 Name Constraints Name verification
Related 1.5 Certificate Policy Define policy

« <- 5.3 Revocation Check | ^ Validation Overview | 5.5 Name Constraints -> »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional