# PIV Smart Card Authentication Implementation Plan

**Version:** 2.1  
**Date:** January 2025  
**Document Purpose:** Detailed implementation plan for adding PIV (Personal Identity Verification) smart card authentication to SurePassID MFA Server

---

## Table of Contents

1. [Executive Summary](#executive-summary)
2. [Enrollment & Authentication Methods Summary](#enrollment--authentication-methods-summary)
3. [High-Level Use Cases](#high-level-use-cases)
4. [Technical Architecture](#technical-architecture)
5. [Project Structure & Framework Targeting](#project-structure--framework-targeting)
6. [Implementation Phases](#implementation-phases)
- [Phase 1: Data Model & Enumerations (.NET Standard 2.0)](#phase-1-data-model--enumerations-net-standard-20)
- [Phase 2: Core PIV Infrastructure (.NET Standard 2.0)](#phase-2-core-piv-infrastructure-net-standard-20)
- [Phase 3: Database Repository Interfaces (.NET Standard 2.0)](#phase-3-database-repository-interfaces-net-standard-20)
- [Phase 3b: Database Repository Implementations (.NET Framework 4.8)](#phase-3b-database-repository-implementations-net-framework-48)
- [Phase 4: REST API Endpoints (.NET Framework 4.8)](#phase-4-rest-api-endpoints-net-framework-48)
- [Phase 5: API Type Constants](#phase-5-api-type-constants)
- [Phase 6: Integration with Existing APIs](#phase-6-integration-with-existing-apis)
- [Phase 7: Error Codes](#phase-7-error-codes)
- [Phase 8: Configuration](#phase-8-configuration)
- [Phase 9: Audit Logging](#phase-9-audit-logging)
- [Phase 10: Client-Side Integration](#phase-10-client-side-integration)
- [Phase 11: Admin UI Integration](#phase-11-admin-ui-integration)
- [Phase 12: Bulk Certificate Import](#phase-12-bulk-certificate-import)
- [Phase 13: Web Server Header-Based Authentication](#phase-13-web-server-header-based-authentication-net-framework-48)
7. [API Reference](#api-reference)
8. [Database Schema](#database-schema)
9. [Security Considerations](#security-considerations)
10. [Testing Requirements](#testing-requirements)
11. [Implementation Timeline](#implementation-timeline)

---

## Executive Summary

This document provides a comprehensive implementation plan for adding PIV (Personal Identity Verification) smart card authentication support to the SurePassID MFA Server. PIV cards, compliant with FIPS 201, are commonly used in US federal government environments and provide certificate-based authentication using X.509 certificates.

### What is PIV?

PIV (Personal Identity Verification) is a US federal government standard (FIPS 201) for secure, reliable identification of federal employees and contractors. PIV cards contain:

- **X.509 Certificates** for authentication, digital signatures, and encryption
- **PIN Protection** for card access
- **Biometric Data** (optional) for identity verification
- **Multiple Key Slots** for different purposes (authentication, signing, key management)

### Key PIV Card Components

| Key Slot | OID | Purpose |
|----------|-----|---------|
| 9A | PIV Authentication | General authentication to systems |
| 9C | Digital Signature | Document signing (non-repudiation) |
| 9D | Key Management | Encryption/decryption operations |
| 9E | Card Authentication | Contactless authentication (no PIN required) |

---

## Enrollment & Authentication Methods Summary

This implementation supports multiple methods for enrolling and authenticating PIV certificates. The table below summarizes the available options:

### Enrollment Methods

| Method | Interface | Challenge-Response | Use Case | Implementation Phase |
|--------|-----------|-------------------|----------|---------------------|
| **Self-Service Enrollment** | REST API | ? Required | User enrolls own PIV card with card present | Phase 4, 10 |
| **Admin Manual Enrollment** | Admin UI | ? Not Required | Admin uploads certificate file for user | Phase 11 |
| **Bulk Certificate Import** | Admin UI | ? Not Required | Import multiple certificates via CSV | Phase 12 |
| **API Direct Enrollment** | REST API | ? Optional | Trusted system enrolls certificate without challenge | Phase 4 (extended) |

### Authentication Methods

| Method | Interface | Challenge-Response | Use Case | Implementation Phase |
|--------|-----------|-------------------|----------|---------------------|
| **Challenge-Response Auth** | REST API | ? Required | Standard PIV authentication with card present | Phase 4 |
| **VPN/RADIUS Auth** | RADIUS | ? Required | Network access authentication | Phase 6 |
| **Web SSO (SAML2)** | SAML2 IdP | ? Required | Single sign-on for web applications | Phase 6 |
| **Header-Based Auth (IIS/NGINX)** | REST API | ? Not Required | TLS termination at web server | Phase 13 |

### When to Use Each Enrollment Method

| Scenario | Recommended Method | Reason |
|----------|-------------------|--------|
| User has PIV card, can authenticate | Self-Service (REST API) | Proves key possession |
| New employee onboarding (card not available) | Admin Manual (UI) | Admin can upload exported cert |
| Large deployment / migration | Bulk Import (CSV) | Efficiency for many users |
| Automated provisioning system | API Direct Enrollment | System-to-system integration |

### Web Server TLS Client Certificate Authentication

In enterprise deployments, TLS client certificate authentication is often handled at the web server level (IIS or NGINX) rather than at the application level. In this scenario:

1. **Web Server** (IIS/NGINX) terminates TLS and validates the client certificate
2. **Web Server** extracts certificate information and passes it via HTTP headers
3. **MFA Server** receives headers and validates against enrolled certificates

**Common Headers (configurable):**

| Header | Description | Example Value |
|--------|-------------|---------------|
| `X-Client-Cert` | Base64-encoded client certificate | `MIIEpDCCA4yg...` |
| `X-Client-Cert-Subject` | Certificate Subject DN | `CN=John Doe, OU=Agency, O=Gov, C=US` |
| `X-Client-Cert-Issuer` | Certificate Issuer DN | `CN=Agency CA, O=Gov, C=US` |
| `X-Client-Cert-Serial` | Certificate serial number | `1234567890ABCDEF` |
| `X-Client-Cert-Fingerprint` | SHA-256 fingerprint | `A1B2C3D4...` |
| `X-Client-Cert-Valid` | Validation result from web server | `SUCCESS` or `FAILED` |
| `X-Client-Cert-Verify` | NGINX verification result | `SUCCESS`, `FAILED:reason` |
| `SSL_CLIENT_S_DN` | IIS-style Subject DN | `CN=John Doe...` |
| `SSL_CLIENT_CERT` | IIS-style certificate | PEM-encoded certificate |

---

## High-Level Use Cases

### Use Case 1: Federal Employee VPN Access

**Actor:** Federal government employee  
**Preconditions:** Employee has issued PIV card, VPN configured for PIV authentication  
**Flow:**
1. Employee inserts PIV card into smart card reader
2. Employee initiates VPN connection
3. VPN client sends authentication request to MFA server
4. MFA server returns challenge
5. Employee enters PIV PIN
6. PIV card signs challenge with private key (never leaves card)
7. MFA server validates signature against enrolled certificate
8. VPN access granted

**Value:** Enables HSPD-12 compliant authentication for remote access.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 3-4 | Challenge Generation | Phase 2, 4 | `piv_pre_auth` API, `IPivChallengeService` |
| 6 | Client-side signing | Phase 10 | Client middleware (CryptoAPI/PKCS#11) |
| 7 | Signature Verification | Phase 2 | `IPivCertificateService.VerifySignedChallenge()` |
| 7 | Certificate Validation | Phase 2 | `IPivCertificateService.ValidateCertificateChain()` |
| 7 | Revocation Check | Phase 2 | `IPivRevocationService.CheckRevocationStatusAsync()` |
| 8 | Session Token | Phase 4 | `piv_auth` API response |

---

### Use Case 2: PIV + OTP Multi-Factor Authentication

**Actor:** High-security environment user  
**Preconditions:** User has PIV card and mobile authenticator enrolled  
**Flow:**
1. User authenticates with PIV certificate (something you have + something you know - PIN)
2. System prompts for additional OTP factor
3. User provides OTP from mobile authenticator
4. Both factors validated, access granted

**Value:** Combines certificate-based identity verification with possession-based OTP for defense-in-depth.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 1 | PIV Authentication | Phase 4 | `piv_pre_auth` ? `piv_auth` flow |
| 1 | Certificate Validation | Phase 2 | `IPivCertificateService` |
| 2-3 | OTP Validation | Existing | `validate_otp` API (existing) |
| 4 | Combined Validation | Phase 6 | `validate_user` API (extended) |

---

### Use Case 3: Contractor Onboarding with PIV Enrollment

**Actor:** IT Administrator / New contractor  
**Preconditions:** Contractor has been issued PIV card  
**Flow:**
1. Administrator initiates PIV enrollment for new user
2. System generates enrollment challenge
3. Contractor inserts PIV card and enters PIN
4. Card signs challenge, certificate is submitted
5. System validates certificate chain against trusted CAs
6. System checks certificate revocation status
7. Certificate enrolled and linked to user account

**Value:** Self-service enrollment reduces IT burden while maintaining security.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 1-2 | Enrollment Initiation | Phase 4 | `piv_pre_enroll` API |
| 2 | Challenge Generation | Phase 2 | `IPivChallengeService.CreateChallenge()` |
| 3 | Client-side signing | Phase 10 | Browser Web Crypto API / Windows CryptoAPI |
| 4 | Certificate Submission | Phase 4 | `piv_enroll` API |
| 5 | Chain Validation | Phase 2 | `IPivCertificateService.ValidateCertificateChain()` |
| 5 | Trusted CA Lookup | Phase 3b | `InterfacePivTrustedCA.GetEnabledByPartnerId()` |
| 6 | Revocation Check | Phase 2 | `IPivRevocationService.CheckRevocationStatusAsync()` |
| 7 | Certificate Storage | Phase 3b | `InterfaceDevicePivCertificate.Add()` |
| 7 | Device Creation | Phase 4 | `InterfaceDevice` (existing, extended) |

**Alternative Flow (Admin Enrollment):**
- Steps 1-4 replaced by: Admin uploads certificate file via Admin UI (Phase 11)
- No challenge-response required when admin has certificate file

---

### Use Case 4: Web Application Single Sign-On

**Actor:** Government agency web application user  
**Preconditions:** User has PIV card, web application configured for SAML2 SSO  
**Flow:**
1. User accesses protected web application
2. Application redirects to SurePassID IdP
3. IdP prompts for PIV authentication
4. User inserts card, enters PIN, browser signs challenge
5. IdP validates signature and certificate
6. SAML assertion generated with PIV-validated identity
7. User redirected to application with SSO session

**Value:** Seamless single sign-on experience with hardware-based credentials.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 2-3 | IdP PIV Prompt | Phase 6, 10 | SAML2 IdP integration + Browser JS |
| 3-4 | Challenge-Response | Phase 4 | `piv_pre_auth` ? `piv_auth` flow |
| 4 | Browser Signing | Phase 10 | Web Crypto API / Smart Card middleware |
| 5 | Signature Verification | Phase 2 | `IPivCertificateService` |
| 5 | Revocation Check | Phase 2 | `IPivRevocationService` |
| 6 | SAML Assertion | Existing | SAML2 IdP (existing, extended for PIV) |

---

### Use Case 5: Passwordless Authentication

**Actor:** Security-conscious enterprise user  
**Preconditions:** PIV card enrolled for user, passwordless authentication enabled  
**Flow:**
1. User navigates to login page
2. User selects "Sign in with Smart Card"
3. User inserts PIV card and enters PIN
4. System validates certificate and signature
5. User authenticated without entering any password

**Value:** Eliminates password-related vulnerabilities (phishing, password reuse, credential stuffing).

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 2 | PIV Auth Option | Phase 10, 11 | Login page UI integration |
| 3 | Challenge Request | Phase 4 | `piv_pre_auth` API |
| 3 | Client Signing | Phase 10 | Browser/Desktop client |
| 4 | Signature Verification | Phase 2, 4 | `piv_auth` API, `IPivCertificateService` |
| 4 | Revocation Check | Phase 2 | `IPivRevocationService` |
| 5 | Session Token | Phase 4 | `piv_auth` response `sessionToken` |

---

### Use Case 6: PIV Card Lifecycle Management

**Actor:** Security administrator  
**Preconditions:** PIV certificates enrolled in system  
**Flow:**
1. Administrator views PIV certificate dashboard
2. System displays certificates approaching expiration
3. Administrator reviews revocation status reports
4. System automatically checks CRL/OCSP for enrolled certificates
5. Administrator disables/removes expired or revoked certificates

**Value:** Centralized management of certificate-based credentials with proactive lifecycle monitoring.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 1-2 | Certificate Dashboard | Phase 11 | Admin UI - PIV device list |
| 2 | Expiration Query | Phase 3b | `InterfaceDevicePivCertificate.GetExpiringSoon()` |
| 3-4 | Revocation Status | Phase 2 | `IPivRevocationService` |
| 4 | Background Check | Phase 8 | Scheduled task / configuration |
| 5 | Certificate Removal | Phase 4, 11 | `piv_delete_device` API / Admin UI |
| 5 | Status Update | Phase 3b | `InterfaceDevicePivCertificate.UpdateRevocationStatus()` |

---

### Use Case 7: Bulk PIV Certificate Import (New)

**Actor:** IT Administrator  
**Preconditions:** Organization has exported PIV certificates from PKI or card management system  
**Flow:**
1. Administrator prepares CSV file with username and certificate data
2. Administrator accesses PIV Import page in Admin Console
3. Administrator uploads CSV file
4. System validates each certificate (chain, policy, expiration)
5. System checks for duplicate certificates
6. Valid certificates are enrolled and linked to user accounts
7. Administrator reviews import results and error log

**Value:** Efficient bulk onboarding for large deployments or migrations.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 1 | CSV Format | Phase 12 | Documentation |
| 2-3 | Import UI | Phase 12 | `deviceimportpiv.aspx` |
| 4 | Certificate Validation | Phase 2 | `IPivCertificateService.ValidateCertificateChain()` |
| 4 | Policy Validation | Phase 2 | `IPivCertificateService.ValidatePivPolicy()` |
| 5 | Duplicate Check | Phase 3b | `InterfaceDevicePivCertificate.GetByCertificateHash()` |
| 6 | Bulk Insert | Phase 12 | `InterfaceDevicePivCertificate` (batch operations) |
| 7 | Import Results | Phase 12 | Import results page |

---

### Use Case 8: Web Server TLS Client Certificate Authentication (IIS/NGINX)

**Actor:** Enterprise user accessing web application through IIS or NGINX reverse proxy  
**Preconditions:** 
- PIV card enrolled for user in MFA server
- IIS/NGINX configured for TLS client certificate authentication
- Web server configured to pass certificate info via headers

**Flow:**
1. User accesses protected web application via HTTPS
2. Web server (IIS/NGINX) requests client certificate during TLS handshake
3. User's PIV card provides certificate (may prompt for PIN depending on key slot)
4. Web server validates certificate chain and revocation status
5. Web server extracts certificate details and adds to request headers
6. Request reaches MFA server with `X-Client-Cert-*` headers
7. MFA server looks up certificate by fingerprint/subject in enrolled certificates
8. MFA server validates certificate is enrolled for the requesting user
9. User authenticated, session token returned

**Value:** Leverages existing web server PKI infrastructure; no challenge-response needed since TLS handshake proves key possession.

#### Implementation Components

| Step | Component | Phase | API/Service |
|------|-----------|-------|-------------|
| 5-6 | Header Extraction | Phase 13 | `PivHeaderAuthMiddleware` |
| 7 | Certificate Lookup | Phase 13 | `piv_header_auth` API |
| 7 | Fingerprint Match | Phase 3b | `InterfaceDevicePivCertificate.GetByCertificateHash()` |
| 8 | User Validation | Phase 13 | `IPivCertificateService` |
| 9 | Session Token | Phase 4 | Session token generation |

#### IIS Configuration Example

```xml
<!-- web.config for IIS client certificate authentication -->
<system.webServer>
    <security>
        <access sslFlags="Ssl, SslNegotiateCert, SslRequireCert" />
        <authentication>
            <clientCertificateMappingAuthentication enabled="true" />
            <iisClientCertificateMappingAuthentication enabled="true">
                <manyToOneMappings>
                    <add name="PIV Authentication"
                         enabled="true"
                         permissionMode="Allow"
                         userName="PIV_SERVICE_ACCOUNT"
                         password="..." />
                </manyToOneMappings>
            </iisClientCertificateMappingAuthentication>
        </authentication>
    </security>
</system.webServer>
```

#### NGINX Configuration Example

```nginx
# NGINX configuration for client certificate authentication
server {
    listen 443 ssl;
    server_name mfa.example.gov;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;
    
    # Client certificate settings
    ssl_client_certificate /etc/nginx/certs/trusted-cas.pem;
    ssl_verify_client optional_no_ca;  # or 'on' for strict validation
    ssl_verify_depth 3;

    location /api/ {
        # Pass certificate info to upstream
        proxy_set_header X-Client-Cert $ssl_client_escaped_cert;
        proxy_set_header X-Client-Cert-Subject $ssl_client_s_dn;
        proxy_set_header X-Client-Cert-Issuer $ssl_client_i_dn;
        proxy_set_header X-Client-Cert-Serial $ssl_client_serial;
        proxy_set_header X-Client-Cert-Fingerprint $ssl_client_fingerprint;
        proxy_set_header X-Client-Cert-Verify $ssl_client_verify;
        proxy_set_header X-Client-Cert-Valid-From $ssl_client_v_start;
        proxy_set_header X-Client-Cert-Valid-To $ssl_client_v_end;
        
        proxy_pass http://mfa-backend:8080;
    }
}
```

---

## Technical Architecture

### Component Overview

```
???????????????????????????????????????????????????????????????????????
?                        Client Applications                           ?
?  (Web Browser, VPN Client, Native App, RADIUS Client)               ?
???????????????????????????????????????????????????????????????????????
                                    ?
                                    ?
???????????????????????????????????????????????????????????????????????
?                     SurePassID MFA Server                            ?
?  ???????????????  ???????????????  ???????????????                  ?
?  ? REST API    ?  ? RADIUS      ?  ? SAML2 IdP   ?                  ?
?  ? Endpoints   ?  ? Server      ?  ?             ?                  ?
?  ???????????????  ???????????????  ???????????????                  ?
?         ???????????????????????????????????                          ?
?                          ?                                           ?
?  ???????????????????????????????????????????????????????????????    ?
?  ?                  PIV Authentication Service                   ?    ?
?  ?  ????????????????? ????????????????? ?????????????????      ?    ?
?  ?  ? Certificate   ? ? Challenge     ? ? Revocation    ?      ?    ?
?  ?  ? Validation    ? ? Response      ? ? Checking      ?      ?    ?
?  ?  ????????????????? ????????????????? ?????????????????      ?    ?
?  ???????????????????????????????????????????????????????????????    ?
?                          ?                                           ?
?                          ?                                           ?
?  ???????????????????????????????????????????????????????????????    ?
?  ?                    Database Layer                             ?    ?
?  ?  DevicePivCertificate ? PivTrustedCA ? PivAuthSession        ?    ?
?  ???????????????????????????????????????????????????????????????    ?
???????????????????????????????????????????????????????????????????????
                                    ?
                                    ?
???????????????????????????????????????????????????????????????????????
?                    External Services                                 ?
?  ???????????????  ???????????????                                   ?
?  ? CRL         ?  ? OCSP        ?                                   ?
?  ? Distribution?  ? Responder   ?                                   ?
?  ? Points      ?  ?             ?                                   ?
?  ???????????????  ???????????????                                   ?
???????????????????????????????????????????????????????????????????????
```

### Authentication Flow

```
????????????     ????????????     ????????????     ????????????
?  Client  ?     ?   MFA    ?     ?   PIV    ?     ? Database ?
?          ?     ?  Server  ?     ? Service  ?     ?          ?
????????????     ????????????     ????????????     ????????????
     ?                ?                ?                ?
     ? piv_pre_auth   ?                ?                ?
     ????????????????>?                ?                ?
     ?                ? Get user certs ?                ?
     ?                ????????????????>?                ?
     ?                ?                ? Query certs    ?
     ?                ?                ????????????????>?
     ?                ?                ?<????????????????
     ?                ? Generate       ?                ?
     ?                ? challenge      ?                ?
     ?                ?<????????????????                ?
     ? challenge +    ?                ?                ?
     ? session        ?                ?                ?
     ?<????????????????                ?                ?
     ?                ?                ?                ?
     ? [User enters   ?                ?                ?
     ?  PIN, card     ?                ?                ?
     ?  signs]        ?                ?                ?
     ?                ?                ?                ?
     ? piv_auth       ?                ?                ?
     ? (signed data)  ?                ?                ?
     ????????????????>?                ?                ?
     ?                ? Verify         ?                ?
     ?                ? signature      ?                ?
     ?                ????????????????>?                ?
     ?                ?                ? Check          ?
     ?                ?                ? revocation     ?
     ?                ?                ????????????????>?
     ?                ?                ?      CRL/OCSP  ?
     ?                ?<????????????????                ?
     ? success +      ?                ?                ?
     ? session token  ?                ?                ?
     ?<????????????????                ?                ?
     ?                ?                ?                ?
```

---

## Project Structure & Framework Targeting

### Architecture Decision

The PIV implementation follows a **layered architecture** that separates platform-independent business logic from framework-specific implementations. This approach provides:

- ? **Testability**: Core logic can be tested independently with modern test frameworks (.NET 8)
- ? **Portability**: .NET Standard 2.0 code can be consumed by future .NET 8+ applications
- ? **Maintainability**: Clear separation of concerns between business logic and infrastructure
- ? **Compatibility**: Works with existing .NET Framework 4.8 codebase

### Project Mapping

| Component | Project | Target Framework | Repository |
|-----------|---------|------------------|------------|
| **Core Services** (Interfaces, Models, Business Logic) | `SurePassIdDotNetStdLib` | .NET Standard 2.0 | SurePassIdDotNetLibs |
| **Enumerations & Constants** | `SurePassIdDotNetStdLib` | .NET Standard 2.0 | SurePassIdDotNetLibs |
| **Database Repository Implementations** | `SurePassClassLib` | .NET Framework 4.8 | SurePassIdDotNetLibs |
| **REST API Endpoints** | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | SurePassIdLegacyMfaServer |
| **Unit Tests** | `SurePassIdDotNetStdLibXUnitTests` | .NET 8 | SurePassIdDotNetLibs |

### Directory Structure

```
SurePassIdLegacyMfaServer/                           (.NET Framework 4.8)
??? server/
?   ??? ApiActions/
?       ??? PivPreEnrollment.cs                      # Thin wrapper ? calls service
?       ??? PivEnrollment.cs
?       ??? PivPreAuth.cs
?       ??? PivAuth.cs
?       ??? PivFindDevice.cs
?       ??? PivDeleteDevice.cs
??? Properties/
?   ??? Constants.cs                                 # API type constants
??? docs/
?   ??? PIV_SmartCard_Implementation_Plan.md
??? devicedetail.aspx                                # MODIFIED: Add PIV support
??? devices.aspx                                     # MODIFIED: Add PIV columns
??? pivtrustedca.aspx                                # NEW: Trusted CA management
??? deviceimportpiv1.aspx                            # NEW: PIV import - file upload
??? deviceimportpiv2.aspx                            # NEW: PIV import - column mapping
??? deviceimportpiv3.aspx                            # NEW: PIV import - options
??? deviceimportpiv4.aspx                            # NEW: PIV import - results

Submodules/SurePassIdDotNetLibs/
??? SurePassIdDotNetStdLib/                          (.NET Standard 2.0) ? CORE PIV CODE
?   ??? Services/
?       ??? Piv/
?           ??? Interfaces/
?           ?   ??? IPivCertificateService.cs
?           ?   ??? IPivRevocationService.cs
?           ?   ??? IPivChallengeService.cs
?           ?   ??? IPivCertificateRepository.cs
?           ??? Implementation/
?           ?   ??? PivCertificateService.cs
?           ?   ??? PivRevocationService.cs
?           ?   ??? PivChallengeService.cs
?           ??? Models/
?           ?   ??? PivCertificateInfo.cs
?           ?   ??? PivChallenge.cs
?           ?   ??? CertificateValidationResult.cs
?           ?   ??? RevocationCheckResult.cs
?           ?   ??? ChallengeVerificationResult.cs
?           ??? Constants/
?               ??? PivConstants.cs
?   ??? Enums/
?       ??? PivEnums.cs
?
??? SurePassClassLib/                                (.NET Framework 4.8)
?   ??? Database/
?       ??? TableDevicePivCertificate.cs
?       ??? TablePivTrustedCA.cs
?       ??? TablePivAuthSession.cs
?       ??? InterfaceDevicePivCertificate.cs
?       ??? InterfacePivTrustedCA.cs
?       ??? InterfacePivAuthSession.cs
?
??? SurePassIdDotNetStdLibXUnitTests/                (.NET 8)
    ??? Services/
        ??? Piv/
            ??? PivCertificateServiceTests.cs
            ??? PivRevocationServiceTests.cs
            ??? PivChallengeServiceTests.cs
```

### Key Design Principles

1. **Repository Pattern**: Database access abstracted through interfaces in .NET Standard 2.0, with implementations in .NET Framework 4.8.

2. **Service Layer**: All business logic lives in .NET Standard 2.0 services that depend only on repository interfaces.

3. **Thin API Endpoints**: REST API endpoints are thin wrappers that parse JSON, call services, and format responses.

4. **Dependency Injection Ready**: Services accept repository interfaces via constructor, enabling easy testing.

### .NET Standard 2.0 Compatibility Notes

All X.509/cryptographic APIs work in .NET Standard 2.0:

```csharp
// ? All compatible with .NET Standard 2.0
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

var cert = new X509Certificate2(certBytes);
var chain = new X509Chain();
chain.Build(cert);

using var rsa = cert.GetRSAPublicKey();
bool valid = rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

using var ecdsa = cert.GetECDsaPublicKey();
bool valid = ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);
```

---

## Implementation Phases

### Phase 1: Data Model & Enumerations (.NET Standard 2.0)

#### 1.1 Extend `DeviceTypesEnum`

**File:** `SurePassIdLegacyMfaServer\Properties\Constants.cs`

Add new device type for PIV Smart Card:

```csharp
public enum DeviceTypes
{
    None = -1,
    FOB = 0,
    DesktopAuthenticator = 1,
    ElectronicCard = 4,
    SmartCard = 5,
    MatrixCard = 6,
    CellPhoneSMS = 7,
    GoogleAuthenticator = 8,
    SurePassIDAuthenticatorMobile = 9,
    CellPhoneVoice = 10,
    CellPhoneVoiceNoOTP = 11,
    FidoU2F = 12,
    NymiBand = 13,
    Treo = 14,
    PivSmartCard = 15        // NEW: PIV Smart Card (FIPS 201)
}
```

#### 1.2 Extend `OTPTypesEnum`

**File:** `SurePassIdLegacyMfaServer\Properties\Constants.cs`

Add PIV-specific authentication types:

```csharp
public enum OTPTypes
{
    // ... existing values (0-25) ...
    PIV_Auth = 26,           // PIV Authentication Certificate (Key 9A)
    PIV_Sign = 27,           // PIV Digital Signature Certificate (Key 9C)
    PIV_CardAuth = 28        // PIV Card Authentication (Key 9E - contactless)
}
```

#### 1.3 Extend `ApiPermissionsEnum`

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Enums\ApiPermissionsEnum.cs`

Add PIV-specific permissions:

```csharp
public enum ApiPermissionsEnum
{
    // ... existing values (1-53) ...
    PivEnroll = 54,          // PIV certificate enrollment
    PivAuth = 55,            // PIV authentication
    PivDelete = 56,          // Delete PIV credentials
    PivFind = 57,            // Find PIV devices
    PivRevocationCheck = 58  // Certificate revocation checking
}
```

#### 1.4 New Enumerations

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Enums\PivEnums.cs` (NEW)

```csharp
namespace SurePassClassLib.Enums
{
    /// <summary>
    /// PIV key slot identifiers per FIPS 201
    /// </summary>
    public enum PivKeySlot
    {
        Authentication = 0x9A,    // PIV Authentication
        Signature = 0x9C,         // Digital Signature
        KeyManagement = 0x9D,     // Key Management
        CardAuthentication = 0x9E // Card Authentication
    }

    /// <summary>
    /// Certificate revocation status
    /// </summary>
    public enum RevocationStatus
    {
        Unknown = 0,
        Valid = 1,
        Revoked = 2,
        Suspended = 3,
        CheckFailed = 4
    }

    /// <summary>
    /// PIV authentication session state
    /// </summary>
    public enum PivSessionState
    {
        Pending = 0,
        Completed = 1,
        Failed = 2,
        Expired = 3
    }

    /// <summary>
    /// Revocation check mode
    /// </summary>
    public enum RevocationCheckMode
    {
        Online = 0,      // Always check online
        Cached = 1,      // Use cached status if available
        Offline = 2,     // Only use cached, fail if not available
        Disabled = 3     // Skip revocation checking
    }
}
```

---

### Phase 2: Core PIV Infrastructure (.NET Standard 2.0)

#### 2.1 PIV Certificate Service

**File:** `Submodules\SurePassIdDotNetLibs\SurePassIdDotNetStdLib\Services\Piv\PivCertificateService.cs` (NEW)

**Purpose:** Certificate parsing, validation, and chain verification

**Key Responsibilities:**
- Parse X.509 certificates from DER/PEM format
- Validate certificate chains against trusted CAs
- Check certificate policy OIDs for FIPS 201 compliance
- Extract PIV-specific data (FASC-N, UUID)
- Determine key slot from certificate key usage

**Interface:**

```csharp
public interface IPivCertificateService
{
    /// <summary>
    /// Parse certificate and extract PIV-relevant information
    /// </summary>
    PivCertificateInfo ParseCertificate(byte[] certData);

    /// <summary>
    /// Validate certificate chain against trusted CAs
    /// </summary>
    CertificateValidationResult ValidateCertificateChain(
        X509Certificate2 certificate,
        IEnumerable<X509Certificate2> trustedCAs);

    /// <summary>
    /// Check if certificate contains valid PIV policy OIDs
    /// </summary>
    bool ValidatePivPolicy(X509Certificate2 certificate);

    /// <summary>
    /// Extract FASC-N from certificate subject alternative name
    /// </summary>
    string ExtractFascN(X509Certificate2 certificate);

    /// <summary>
    /// Determine PIV key slot based on certificate key usage
    /// </summary>
    PivKeySlot DetermineKeySlot(X509Certificate2 certificate);

    /// <summary>
    /// Calculate certificate hash for lookup
    /// </summary>
    string CalculateCertificateHash(X509Certificate2 certificate);
}
```

**Model Classes:**

```csharp
public class PivCertificateInfo
{
    public string SubjectDN { get; set; }
    public string IssuerDN { get; set; }
    public string SerialNumber { get; set; }
    public DateTime NotBefore { get; set; }
    public DateTime NotAfter { get; set; }
    public string CertificateHash { get; set; }
    public PivKeySlot KeySlot { get; set; }
    public string FascN { get; set; }
    public string Uuid { get; set; }
    public List<string> PolicyOids { get; set; }
    public bool IsFips201Compliant { get; set; }
}

public class CertificateValidationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
    public X509ChainStatusFlags ChainStatus { get; set; }
    public List<X509Certificate2> CertificateChain { get; set; }
}
```

#### 2.2 Certificate Revocation Service

**File:** `Submodules\SurePassIdDotNetLibs\SurePassIdDotNetStdLib\Services\Piv\PivRevocationService.cs` (NEW)

**Purpose:** CRL and OCSP revocation checking

**Key Responsibilities:**
- Download and cache CRLs from distribution points
- Perform OCSP queries
- Cache revocation status with configurable TTL
- Support offline mode with cached data

**Interface:**

```csharp
public interface IPivRevocationService
{
    /// <summary>
    /// Check certificate revocation status
    /// </summary>
    Task<RevocationCheckResult> CheckRevocationStatusAsync(
        X509Certificate2 certificate,
        X509Certificate2 issuer,
        RevocationCheckMode mode = RevocationCheckMode.Online);

    /// <summary>
    /// Download and cache CRL from distribution point
    /// </summary>
    Task<X509Crl> DownloadCrlAsync(string distributionPoint);

    /// <summary>
    /// Perform OCSP check
    /// </summary>
    Task<OcspResponse> CheckOcspAsync(
        X509Certificate2 certificate,
        X509Certificate2 issuer,
        string ocspResponderUrl);

    /// <summary>
    /// Get cached revocation status
    /// </summary>
    RevocationStatus GetCachedStatus(string certificateHash);

    /// <summary>
    /// Clear revocation cache
    /// </summary>
    void ClearCache();
}

public class RevocationCheckResult
{
    public RevocationStatus Status { get; set; }
    public DateTime CheckTime { get; set; }
    public string RevocationReason { get; set; }
    public DateTime? RevocationDate { get; set; }
    public string CheckMethod { get; set; } // "CRL" or "OCSP"
}
```

#### 2.3 PIV Challenge-Response Service

**File:** `Submodules\SurePassIdDotNetLibs\SurePassIdDotNetStdLib\Services\Piv\PivChallengeService.cs` (NEW)

**Purpose:** Generate and verify cryptographic challenges

**Key Responsibilities:**
- Generate cryptographically random challenges
- Store challenge sessions with expiration
- Verify signed challenges against public key
- Support multiple signature algorithms (RSA, ECDSA)

**Interface:**

```csharp
public interface IPivChallengeService
{
    /// <summary>
    /// Create a new authentication challenge
    /// </summary>
    PivChallenge CreateChallenge(
        int partnerId,
        int? partnerUserId,
        string certificateHash,
        int timeoutMinutes = 5);

    /// <summary>
    /// Verify a signed challenge
    /// </summary>
    ChallengeVerificationResult VerifySignedChallenge(
        string sessionId,
        byte[] signedData,
        X509Certificate2 certificate);

    /// <summary>
    /// Get challenge by session ID
    /// </summary>
    PivChallenge GetChallenge(string sessionId);

    /// <summary>
    /// Mark challenge as completed
    /// </summary>
    void CompleteChallenge(string sessionId, bool success);

    /// <summary>
    /// Cleanup expired challenges
    /// </summary>
    int CleanupExpiredChallenges();
}

public class PivChallenge
{
    public string SessionId { get; set; }
    public byte[] Challenge { get; set; }
    public string ChallengeBase64 { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime ExpiresAt { get; set; }
    public int PartnerId { get; set; }
    public int? PartnerUserId { get; set; }
    public string CertificateHash { get; set; }
    public PivSessionState State { get; set; }
}

public class ChallengeVerificationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
    public string SignatureAlgorithm { get; set; }
}
```

---

### Phase 3: Database Repository Interfaces (.NET Standard 2.0)

#### 3.1 Repository Interfaces

**File:** `Submodules\SurePassIdDotNetLibs\SurePassIdDotNetStdLib\Services\Piv\Interfaces\IPivCertificateRepository.cs` (NEW)

```csharp
namespace SurePassIdDotNetStdLib.Services.Piv.Interfaces
{
    /// <summary>
    /// Repository interface for PIV certificate persistence.
    /// Implementations provided by .NET Framework 4.8 projects using EF6/ADO.NET.
    /// </summary>
    public interface IPivCertificateRepository
    {
        PivCertificateEntity GetById(int id);
        PivCertificateEntity GetByCertificateHash(int partnerId, string hash);
        PivCertificateEntity GetByDeviceId(int deviceId);
        IEnumerable<PivCertificateEntity> GetByPartnerId(int partnerId);
        IEnumerable<PivCertificateEntity> GetByPartnerUserId(int partnerId, int partnerUserId);
        IEnumerable<PivCertificateEntity> GetExpiringSoon(int partnerId, int daysUntilExpiration);
        bool Add(PivCertificateEntity cert);
        bool Update(PivCertificateEntity cert);
        bool Delete(int id);
        bool DeleteByDeviceId(int deviceId);
        bool UpdateRevocationStatus(int id, int status, DateTime checkTime);
    }

    public interface IPivTrustedCaRepository
    {
        PivTrustedCaEntity GetById(int id);
        IEnumerable<PivTrustedCaEntity> GetByPartnerId(int partnerId);
        IEnumerable<PivTrustedCaEntity> GetEnabledByPartnerId(int partnerId);
        IEnumerable<PivTrustedCaEntity> GetRootCAs(int partnerId);
        bool Add(PivTrustedCaEntity ca);
        bool Update(PivTrustedCaEntity ca);
        bool Delete(int id);
        bool SetEnabled(int id, bool enabled);
    }

    public interface IPivAuthSessionRepository
    {
        PivAuthSessionEntity GetBySessionId(string sessionId);
        bool Create(PivAuthSessionEntity session);
        bool UpdateState(string sessionId, int state);
        bool Delete(string sessionId);
        int DeleteExpired();
    }
}
```

#### 3.2 Entity Models (.NET Standard 2.0)

**File:** `Submodules\SurePassIdDotNetLibs\SurePassIdDotNetStdLib\Services\Piv\Models\PivCertificateEntity.cs` (NEW)

```csharp
namespace SurePassIdDotNetStdLib.Services.Piv.Models
{
    /// <summary>
    /// Entity model for PIV certificate storage.
    /// Maps to DevicePivCertificate database table.
    /// </summary>
    public class PivCertificateEntity
    {
        public int Id { get; set; }
        public int DeviceId { get; set; }
        public int PartnerId { get; set; }
        public byte[] Certificate { get; set; }
        public string CertificateHash { get; set; }
        public string SubjectDN { get; set; }
        public string IssuerDN { get; set; }
        public string SerialNumber { get; set; }
        public DateTime NotBefore { get; set; }
        public DateTime NotAfter { get; set; }
        public int KeyUsage { get; set; }
        public string FascN { get; set; }
        public string Uuid { get; set; }
        public int RevocationStatus { get; set; }
        public DateTime? LastRevocationCheck { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime? LastUpdateDate { get; set; }
    }

    public class PivTrustedCaEntity
    {
        public int Id { get; set; }
        public int PartnerId { get; set; }
        public byte[] Certificate { get; set; }
        public string SubjectDN { get; set; }
        public string CertificateHash { get; set; }
        public bool IsRoot { get; set; }
        public string CrlDistributionPoint { get; set; }
        public string OcspResponder { get; set; }
        public bool Enabled { get; set; }
        public DateTime CreatedDate { get; set; }
    }

    public class PivAuthSessionEntity
    {
        public int Id { get; set; }
        public int PartnerId { get; set; }
        public int? PartnerUserId { get; set; }
        public string SessionId { get; set; }
        public byte[] Challenge { get; set; }
        public string CertificateHash { get; set; }
        public int State { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime ExpirationDate { get; set; }
    }
}
```

---

### Phase 3b: Database Repository Implementations (.NET Framework 4.8)

#### 3b.1 Device PIV Certificate Table

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\TableDevicePivCertificate.cs` (NEW)

```csharp
public class TableDevicePivCertificate
{
    public int Id { get; set; }
    public int DeviceId { get; set; }
    public int PartnerId { get; set; }
    public byte[] Certificate { get; set; }
    public string CertificateHash { get; set; }
    public string SubjectDN { get; set; }
    public string IssuerDN { get; set; }
    public string SerialNumber { get; set; }
    public DateTime NotBefore { get; set; }
    public DateTime NotAfter { get; set; }
    public int KeyUsage { get; set; }
    public string FascN { get; set; }
    public string Uuid { get; set; }
    public int RevocationStatus { get; set; }
    public DateTime? LastRevocationCheck { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime? LastUpdateDate { get; set; }
}
```

#### 3b.2 Device PIV Certificate Interface (Repository Implementation)

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\InterfaceDevicePivCertificate.cs` (NEW)

```csharp
public class InterfaceDevicePivCertificate
{
    public TableDevicePivCertificate GetById(Connection conn, int id);
    public TableDevicePivCertificate GetByCertificateHash(Connection conn, int partnerId, string hash);
    public TableDevicePivCertificate GetByDeviceId(Connection conn, int deviceId);
    public List<TableDevicePivCertificate> GetByPartnerId(Connection conn, int partnerId);
    public List<TableDevicePivCertificate> GetByPartnerUserId(Connection conn, int partnerId, int partnerUserId);
    public List<TableDevicePivCertificate> GetExpiringSoon(Connection conn, int partnerId, int daysUntilExpiration);
    public bool Add(Connection conn, TableDevicePivCertificate cert);
    public bool Update(Connection conn, TableDevicePivCertificate cert);
    public bool Delete(Connection conn, int id);
    public bool DeleteByDeviceId(Connection conn, int deviceId);
    public bool UpdateRevocationStatus(Connection conn, int id, int status, DateTime checkTime);
}
```

#### 3b.3 PIV Trusted CA Table and Interface

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\TablePivTrustedCA.cs` (NEW)

```csharp
public class TablePivTrustedCA
{
    public int Id { get; set; }
    public int PartnerId { get; set; }
    public byte[] Certificate { get; set; }
    public string SubjectDN { get; set; }
    public string CertificateHash { get; set; }
    public bool IsRoot { get; set; }
    public string CrlDistributionPoint { get; set; }
    public string OcspResponder { get; set; }
    public bool Enabled { get; set; }
    public DateTime CreatedDate { get; set; }
}
```

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\InterfacePivTrustedCA.cs` (NEW)

```csharp
public class InterfacePivTrustedCA
{
    public TablePivTrustedCA GetById(Connection conn, int id);
    public List<TablePivTrustedCA> GetByPartnerId(Connection conn, int partnerId);
    public List<TablePivTrustedCA> GetEnabledByPartnerId(Connection conn, int partnerId);
    public List<TablePivTrustedCA> GetRootCAs(Connection conn, int partnerId);
    public bool Add(Connection conn, TablePivTrustedCA ca);
    public bool Update(Connection conn, TablePivTrustedCA ca);
    public bool Delete(Connection conn, int id);
    public bool SetEnabled(Connection conn, int id, bool enabled);
}
```

#### 3b.4 PIV Auth Session Table and Interface

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\TablePivAuthSession.cs` (NEW)

```csharp
public class TablePivAuthSession
{
    public int Id { get; set; }
    public int PartnerId { get; set; }
    public int? PartnerUserId { get; set; }
    public string SessionId { get; set; }
    public byte[] Challenge { get; set; }
    public string CertificateHash { get; set; }
    public int State { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ExpirationDate { get; set; }
}
```

**File:** `Submodules\SurePassIdDotNetLibs\SurePassClassLib\Database\InterfacePivAuthSession.cs` (NEW)

```csharp
public class InterfacePivAuthSession
{
    public TablePivAuthSession GetBySessionId(Connection conn, string sessionId);
    public bool Create(Connection conn, TablePivAuthSession session);
    public bool UpdateState(Connection conn, string sessionId, int state);
    public bool Delete(Connection conn, string sessionId);
    public int DeleteExpired(Connection conn);
}
```

---

### Phase 4: REST API Endpoints (.NET Framework 4.8)

This phase creates the REST API endpoints required to use PIV authentication with the MFA server. These endpoints follow the existing `IApiAction` pattern used by other authentication methods.

#### REST API Endpoints Created

| File | API Type | HTTP Method | Purpose |
|------|----------|-------------|---------|
| `PivPreEnrollment.cs` | `piv_pre_enroll` | POST | Initiate PIV certificate enrollment |
| `PivEnrollment.cs` | `piv_enroll` | POST | Complete PIV certificate enrollment |
| `PivPreAuth.cs` | `piv_pre_auth` | POST | Initiate PIV authentication challenge |
| `PivAuth.cs` | `piv_auth` | POST | Complete PIV authentication |
| `PivFindDevice.cs` | `piv_find_device` | POST | Retrieve PIV device information |
| `PivDeleteDevice.cs` | `piv_delete_device` | POST | Delete PIV device/certificate |

All endpoints are accessed via the standard API proxy: `POST /api/ServerProxy.ashx`

#### 4.1 PIV Pre-Enrollment API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivPreEnrollment.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_pre_enroll` |
| **Permission** | `PivEnroll` (54) |
| **Purpose** | Initiate PIV certificate enrollment |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_pre_enroll"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | Yes | User's login name |

**Request Example:**

```json
{
    "type": "piv_pre_enroll",
    "spAccountLoginName": "api-key-id",
    "spAccountLoginKey": "api-key-secret",
    "username": "john.doe"
}
```

**Success Response:**

```json
{
    "type": "piv_pre_enroll",
    "errorCode": 0,
    "errorMessage": "OK",
    "sessionId": "base64-session-id",
    "challenge": "base64-challenge-nonce",
    "supportedAlgorithms": ["RS256", "RS384", "RS512", "ES256", "ES384"]
}
```

---

#### 4.2 PIV Enrollment API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivEnrollment.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_enroll` |
| **Permission** | `PivEnroll` (54) |
| **Purpose** | Complete PIV certificate enrollment |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_enroll"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | Yes | User's login name |
| `sessionId` | string | Yes | Session ID from pre_enroll |
| `certificate` | string | Yes | Base64 DER-encoded X.509 certificate |
| `signedChallenge` | string | Yes | Base64 signed challenge |
| `deviceName` | string | No | Friendly name for the PIV device |

**Request Example:**

```json
{
    "type": "piv_enroll",
    "spAccountLoginName": "api-key-id",
    "spAccountLoginKey": "api-key-secret",
    "username": "john.doe",
    "sessionId": "base64-session-id",
    "certificate": "MIIEpDCCA4ygAwIBAgIJ...",
    "signedChallenge": "base64-signed-challenge",
    "deviceName": "My PIV Card"
}
```

**Success Response:**

```json
{
    "type": "piv_enroll",
    "errorCode": 0,
    "errorMessage": "OK",
    "deviceId": "generated-device-id",
    "psn": "PIV-A1B2C3D4",
    "subjectDN": "CN=John Doe, OU=Agency, O=Government, C=US",
    "expirationDate": "2027-01-15T00:00:00Z",
    "keySlot": "9A"
}
```

---

#### 4.3 PIV Pre-Authentication API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivPreAuth.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_pre_auth` |
| **Permission** | `PivAuth` (55) |
| **Purpose** | Initiate PIV authentication challenge |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_pre_auth"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | Yes | User's login name |
| `certificateHash` | string | No | Specific certificate to use |

**Request Example:**

```json
{
    "type": "piv_pre_auth",
    "spAccountLoginName": "api-key-id",
    "spAccountLoginKey": "api-key-secret",
    "username": "john.doe"
}
```

**Success Response:**

```json
{
    "type": "piv_pre_auth",
    "errorCode": 0,
    "errorMessage": "OK",
    "sessionId": "base64-session-id",
    "challenge": "base64-challenge-nonce",
    "registeredCertificates": [
        {
            "certificateHash": "sha256-hash",
            "subjectDN": "CN=John Doe, OU=Agency, O=Government, C=US",
            "keySlot": "9A",
            "deviceName": "My PIV Card",
            "expirationDate": "2027-01-15T00:00:00Z"
        }
    ]
}
```

---

#### 4.4 PIV Authentication API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivAuth.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_auth` |
| **Permission** | `PivAuth` (55) |
| **Purpose** | Complete PIV authentication |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_auth"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | Yes | User's login name |
| `sessionId` | string | Yes | Session ID from piv_pre_auth |
| `signedChallenge` | string | Yes | Base64 signed challenge |
| `certificateHash` | string | No | Certificate hash used for signing |
| `sessionTokenDurationMinutes` | int | No | Session token duration (default: 30) |

**Request Example:**

```json
{
    "type": "piv_auth",
    "spAccountLoginName": "api-key-id",
    "spAccountLoginKey": "api-key-secret",
    "username": "john.doe",
    "sessionId": "base64-session-id",
    "signedChallenge": "base64-signed-challenge",
    "certificateHash": "sha256-hash"
}
```

**Success Response:**

```json
{
    "type": "piv_auth",
    "errorCode": 0,
    "errorMessage": "OK",
    "sessionToken": "generated-session-token",
    "certificateSubject": "CN=John Doe, OU=Agency, O=Government, C=US",
    "keySlot": "9A"
}
```

---

#### 4.5 PIV Find Device API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivFindDevice.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_find_device` |
| **Permission** | `PivFind` (57) |
| **Purpose** | Retrieve PIV device information |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_find_device"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | No | User's login name |
| `psn` | string | No | Printed serial number |
| `certificateHash` | string | No | Certificate hash |

**Success Response:**

```json
{
    "type": "piv_find_device",
    "errorCode": 0,
    "errorMessage": "OK",
    "deviceId": "device-id",
    "psn": "PIV-A1B2C3D4",
    "deviceType": 15,
    "otpType": 26,
    "deviceStatus": 0,
    "username": "john.doe",
    "certificate": {
        "subjectDN": "CN=John Doe, OU=Agency, O=Government, C=US",
        "issuerDN": "CN=Agency CA, O=Government, C=US",
        "serialNumber": "1234567890",
        "notBefore": "2024-01-15T00:00:00Z",
        "notAfter": "2027-01-15T00:00:00Z",
        "keySlot": "9A",
        "fascN": "1234567890123456789012345",
        "revocationStatus": "Valid",
        "lastRevocationCheck": "2025-01-10T12:00:00Z"
    }
}
```

---

#### 4.6 PIV Delete Device API

**File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivDeleteDevice.cs` (NEW)

**API Specification:**

| Property | Value |
|----------|-------|
| **Type** | `piv_delete_device` |
| **Permission** | `PivDelete` (56) |
| **Purpose** | Delete a PIV device/certificate |

**Request Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | Yes | `"piv_delete_device"` |
| `spAccountLoginName` | string | Yes | API Key ID |
| `spAccountLoginKey` | string | Yes | API Key Secret |
| `username` | string | Yes | User's login name |
| `psn` | string | No | Printed serial number |
| `certificateHash` | string | No | Certificate hash |

**Success Response:**

```json
{
    "type": "piv_delete_device",
    "errorCode": 0,
    "errorMessage": "OK"
}
```

---

### Phase 5: API Type Constants

**File:** `SurePassIdLegacyMfaServer\Properties\Constants.cs`

Add PIV API type constants:

```csharp
// PIV Authentication APIs
public const string PIV_PRE_ENROLL = "piv_pre_enroll";
public const string PIV_ENROLL = "piv_enroll";
public const string PIV_PRE_AUTH = "piv_pre_auth";
public const string PIV_AUTH = "piv_auth";
public const string PIV_FIND_DEVICE = "piv_find_device";
public const string PIV_DELETE_DEVICE = "piv_delete_device";
public const string PIV_HEADER_AUTH = "piv_header_auth";  // Header-based auth (IIS/NGINX)
```

---

### Phase 6: Integration with Existing APIs

#### 6.1 Update `validate_user` API

Extend to support PIV as an authentication method:

- Add `authMethod` parameter to specify PIV authentication
- Return PIV devices in device list when `noAuth=1`

#### 6.2 Update `find_user` API

Include PIV devices in the `Devices` array:

```json
{
    "Devices": [
        {
            "deviceType": 15,
            "otpType": 26,
            "psn": "PIV-A1B2C3D4",
            "deviceStatus": 0,
            "tokenAlias": "My PIV Card",
            "pivCertificate": {
                "subjectDN": "CN=John Doe...",
                "expirationDate": "2027-01-15T00:00:00Z",
                "keySlot": "9A"
            }
        }
    ]
}
```

#### 6.3 Update `get_verified_methods` API

Include PIV as available verification method:

```json
{
    "verificationMethods": [
        { "method": "otp", "available": true },
        { "method": "push", "available": true },
        { "method": "piv", "available": true, "certificates": 1 }
    ]
}
```

---

### Phase 7: Error Codes

Add PIV-specific error codes:

| Code | Name | Description |
|------|------|-------------|
| 9200 | PivCertificateInvalid | PIV certificate is invalid or malformed |
| 9201 | PivCertificateExpired | PIV certificate has expired |
| 9202 | PivCertificateRevoked | PIV certificate has been revoked |
| 9203 | PivCertificateNotTrusted | PIV certificate chain validation failed |
| 9204 | PivChallengeInvalid | Signed challenge verification failed |
| 9205 | PivSessionExpired | PIV authentication session has expired |
| 9206 | PivNoCertificatesEnrolled | User has no PIV certificates enrolled |
| 9207 | PivPolicyViolation | Certificate does not meet PIV policy requirements |
| 9208 | PivRevocationCheckFailed | Unable to verify certificate revocation status |
| 9209 | PivKeySlotNotAllowed | Certificate key slot is not allowed |
| 9210 | PivCertificateAlreadyEnrolled | Certificate is already enrolled for another user |

---

### Phase 8: Configuration

**New Configuration Parameters:**

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `Piv.Enabled` | bool | false | Enable PIV authentication |
| `Piv.RequireRevocationCheck` | bool | true | Require online revocation checking |
| `Piv.RevocationCheckMode` | string | "Online" | Online, Cached, Offline, or Disabled |
| `Piv.CrlCacheDurationMinutes` | int | 60 | How long to cache CRL data |
| `Piv.OcspCacheDurationMinutes` | int | 5 | How long to cache OCSP responses |
| `Piv.SessionTimeoutMinutes` | int | 5 | Auth challenge session timeout |
| `Piv.RequireFips201Policy` | bool | true | Require FIPS 201 policy OIDs |
| `Piv.AllowedKeySlots` | string | "9A,9E" | Comma-separated list of allowed key slots |
| `Piv.AllowSelfSignedCerts` | bool | false | Allow self-signed certificates (testing only) |
| `Piv.MaxCertificatesPerUser` | int | 5 | Maximum PIV certificates per user |

**Configuration in web.config:**

```xml
<appSettings>
    <add key="Piv.Enabled" value="true" />
    <add key="Piv.RequireRevocationCheck" value="true" />
    <add key="Piv.RevocationCheckMode" value="Online" />
    <add key="Piv.CrlCacheDurationMinutes" value="60" />
    <add key="Piv.SessionTimeoutMinutes" value="5" />
    <add key="Piv.RequireFips201Policy" value="true" />
    <add key="Piv.AllowedKeySlots" value="9A,9E" />
</appSettings>
```

---

### Phase 9: Audit Logging

#### New Audit Actions

Add to `AuditAction` class:

```csharp
public static readonly AuditAction PivEnroll = new AuditAction(50, "PIV Enrollment");
public static readonly AuditAction PivAuth = new AuditAction(51, "PIV Authentication");
public static readonly AuditAction PivDelete = new AuditAction(52, "PIV Delete");
public static readonly AuditAction PivRevocationCheck = new AuditAction(53, "PIV Revocation Check");
```

#### Audit Log Events

| Event | Action | Severity | Description |
|-------|--------|----------|-------------|
| PIV enrollment initiated | PivEnroll | Information | User started PIV enrollment |
| PIV enrollment completed | PivEnroll | Information | Certificate successfully enrolled |
| PIV enrollment failed | PivEnroll | Warning | Enrollment failed (with reason) |
| PIV authentication initiated | PivAuth | Information | User started PIV authentication |
| PIV authentication succeeded | PivAuth | Information | User successfully authenticated |
| PIV authentication failed | PivAuth | Warning | Authentication failed (with reason) |
| PIV certificate deleted | PivDelete | Information | Certificate removed from user |
| PIV certificate revoked detected | PivRevocationCheck | ActionRequired | Enrolled certificate found revoked |
| PIV certificate expired | PivRevocationCheck | ActionRequired | Enrolled certificate has expired |

---

### Phase 10: Client-Side Integration

#### 10.1 Browser Integration (Web Crypto API)

**Supported Browsers:**
- Chrome 67+ (with smart card middleware)
- Firefox 60+ (with smart card middleware)
- Edge 79+ (with smart card middleware)
- Safari 14+ (macOS with smart card middleware)

**Required Middleware:**
- Windows: Native CryptoAPI/CNG
- macOS: Keychain Access with smart card support
- Linux: OpenSC, PKCS#11 module

**JavaScript Example:**

```javascript
// PIV authentication using Web Crypto API
async function pivAuthenticate(username) {
    // Step 1: Get challenge from server
    const preAuthResponse = await fetch('/api/ServerProxy.ashx', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            type: 'piv_pre_auth',
            spAccountLoginName: apiKeyId,
            spAccountLoginKey: apiKeySecret,
            username: username
        })
    });
    const preAuth = await preAuthResponse.json();
    
    if (preAuth.errorCode !== 0) {
        throw new Error(preAuth.errorMessage);
    }
    
    // Step 2: Sign challenge with PIV card
    // This requires browser support for smart card access
    const challenge = Uint8Array.from(atob(preAuth.challenge), c => c.charCodeAt(0));
    
    // Get certificate from smart card (browser prompts for card/PIN)
    const certificate = await navigator.credentials.get({
        publicKey: {
            challenge: challenge,
            allowCredentials: [], // Allow any credential
            userVerification: 'required'
        }
    });
    
    // Step 3: Send signed challenge to server
    const authResponse = await fetch('/api/ServerProxy.ashx', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            type: 'piv_auth',
            spAccountLoginName: apiKeyId,
            spAccountLoginKey: apiKeySecret,
            username: username,
            sessionId: preAuth.sessionId,
            signedChallenge: btoa(String.fromCharCode(...new Uint8Array(certificate.response.signature)))
        })
    });
    
    return await authResponse.json();
}
```

#### 10.2 Windows Integration (.NET)

**Example using Windows CryptoAPI:**

```csharp
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class PivAuthenticator
{
    public async Task<string> AuthenticateAsync(string username)
    {
        // Step 1: Get certificate from smart card
        var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly);
        
        var certificates = store.Certificates
            .Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, true)
            .OfType<X509Certificate2>()
            .Where(c => IsPivCertificate(c))
            .ToList();
        
        if (!certificates.Any())
            throw new Exception("No PIV certificates found");
        
        var cert = certificates.First(); // Or prompt user to select
        
        // Step 2: Get challenge from server
        var preAuth = await _apiClient.PivPreAuthAsync(username);
        
        // Step 3: Sign challenge
        using var rsa = cert.GetRSAPrivateKey();
        var signature = rsa.SignData(
            Convert.FromBase64String(preAuth.Challenge),
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);
        
        // Step 4: Complete authentication
        return await _apiClient.PivAuthAsync(
            username,
            preAuth.SessionId,
            Convert.ToBase64String(signature));
    }
    
    private bool IsPivCertificate(X509Certificate2 cert)
        {
            // Check for PIV policy OIDs
            return cert.Extensions
                .OfType<X509Extension>()
                .Any(e => e.Oid.Value == "2.16.840.1.101.3.2.1.3.13"); // id-fpki-common-authentication
        }
    }
    ```

    ---

    ### Phase 11: Admin UI Integration (.NET Framework 4.8)

    This phase adds PIV certificate management to the Admin Console, enabling administrators to enroll, view, and manage PIV certificates through the web UI.

    #### 11.1 Device Detail Page Enhancement

    **File:** `SurePassIdLegacyMfaServer\devicedetail.aspx` (MODIFY)

    **Changes:**
    - Add PIV Smart Card as device type option in dropdown
    - Show PIV-specific fields when device type is PIV Smart Card
    - Add certificate upload control for admin enrollment
    - Display certificate details (Subject, Issuer, Expiration, Key Slot)

    **New UI Elements:**

    ```html
    <!-- PIV Certificate Section (visible when DeviceType = PivSmartCard) -->
    <tr runat="server" id="trPivCertificate" visible="false">
        <td align="right">
            <asp:Label ID="lblPivCertificate" runat="server" Text="PIV Certificate" />
        </td>
        <td align="left">
            <asp:FileUpload ID="fuPivCertificate" runat="server" />
            <asp:Label ID="lblPivCertificateFormats" runat="server" 
                Text="Supported formats: DER (.cer, .crt), PEM (.pem)" CssClass="helptext" />
        </td>
    </tr>
    <tr runat="server" id="trPivCertificateDetails" visible="false">
        <td align="right">
            <asp:Label ID="lblPivSubject" runat="server" Text="Subject" />
        </td>
        <td align="left">
            <asp:TextBox ID="tbxPivSubject" runat="server" Enabled="false" size="60" />
        </td>
    </tr>
    <tr runat="server" id="trPivIssuer" visible="false">
        <td align="right">
            <asp:Label ID="lblPivIssuer" runat="server" Text="Issuer" />
        </td>
        <td align="left">
            <asp:TextBox ID="tbxPivIssuer" runat="server" Enabled="false" size="60" />
        </td>
    </tr>
    <tr runat="server" id="trPivKeySlot" visible="false">
        <td align="right">
            <asp:Label ID="lblPivKeySlot" runat="server" Text="Key Slot" />
        </td>
        <td align="left">
            <asp:DropDownList ID="ddlPivKeySlot" runat="server">
                <asp:ListItem Value="9A" Text="9A - PIV Authentication" />
                <asp:ListItem Value="9C" Text="9C - Digital Signature" />
                <asp:ListItem Value="9E" Text="9E - Card Authentication" />
            </asp:DropDownList>
        </td>
    </tr>
    <tr runat="server" id="trPivRevocationStatus" visible="false">
        <td align="right">
            <asp:Label ID="lblPivRevocationStatus" runat="server" Text="Revocation Status" />
        </td>
        <td align="left">
            <asp:Label ID="lblPivRevocationStatusValue" runat="server" />
            <asp:Button ID="btnCheckRevocation" runat="server" Text="Check Now" 
                OnClick="btnCheckRevocation_Click" />
        </td>
    </tr>
    ```

    **Code-Behind Changes:**

    ```csharp
    // devicedetail.aspx.cs additions
    protected void ddlDevice_TypeData_SelectedIndexChanged(object sender, EventArgs e)
    {
        var deviceType = ddlDevice_TypeData.SelectedValue.ToInt16();
    
        // Show/hide PIV-specific fields
        var isPivDevice = deviceType == (short)DeviceTypesEnum.PivSmartCard;
        trPivCertificate.Visible = isPivDevice && !IsUpdate;
        trPivCertificateDetails.Visible = isPivDevice && IsUpdate;
        trPivIssuer.Visible = isPivDevice && IsUpdate;
        trPivKeySlot.Visible = isPivDevice;
        trPivRevocationStatus.Visible = isPivDevice && IsUpdate;
    
        // ... existing code ...
    }

    protected void SavePivCertificate(Connection conn, int deviceId, int partnerId)
    {
        if (fuPivCertificate.HasFile)
        {
            var certBytes = fuPivCertificate.FileBytes;
            var pivCertService = new PivCertificateService();
            var certInfo = pivCertService.ParseCertificate(certBytes);
        
            // Validate certificate
            var trustedCAs = GetTrustedCAs(conn, partnerId);
            var validationResult = pivCertService.ValidateCertificateChain(
                new X509Certificate2(certBytes), trustedCAs);
        
            if (!validationResult.IsValid)
            {
                DisplayFormErrorMsg(validationResult.ErrorMessage, Color.Red);
                return;
            }
        
            // Store certificate
            var interfacePivCert = new InterfaceDevicePivCertificate();
            var pivCert = new TableDevicePivCertificate
            {
                DeviceId = deviceId,
                PartnerId = partnerId,
                Certificate = certBytes,
                CertificateHash = certInfo.CertificateHash,
                SubjectDN = certInfo.SubjectDN,
                IssuerDN = certInfo.IssuerDN,
                SerialNumber = certInfo.SerialNumber,
                NotBefore = certInfo.NotBefore,
                NotAfter = certInfo.NotAfter,
                KeyUsage = (int)certInfo.KeySlot,
                FascN = certInfo.FascN,
                Uuid = certInfo.Uuid,
                RevocationStatus = (int)RevocationStatus.Unknown,
                CreatedDate = DateTime.UtcNow
            };
        
            interfacePivCert.Add(conn, pivCert);
        }
    }

    protected void btnCheckRevocation_Click(object sender, EventArgs e)
    {
        // Trigger on-demand revocation check
        var conn = new Connection();
        try
        {
            if (conn.Connect())
            {
                conn.OpenConnection();
                var pivCert = GetCurrentPivCertificate(conn);
                if (pivCert != null)
                {
                    var revocationService = new PivRevocationService();
                    var result = revocationService.CheckRevocationStatusAsync(
                        new X509Certificate2(pivCert.Certificate),
                        GetIssuerCertificate(conn, pivCert),
                        RevocationCheckMode.Online).Result;
                
                    UpdateRevocationStatusDisplay(result);
                
                    // Update database
                    var interfacePivCert = new InterfaceDevicePivCertificate();
                    interfacePivCert.UpdateRevocationStatus(
                        conn, pivCert.Id, (int)result.Status, result.CheckTime);
                }
            }
        }
        finally
        {
            conn.CloseConnection();
        }
    }
    ```

    #### 11.2 PIV Trusted CA Management Page

    **File:** `SurePassIdLegacyMfaServer\pivtrustedca.aspx` (NEW)

    **Purpose:** Manage trusted Certificate Authorities for PIV certificate validation

    **Features:**
    - List all trusted CAs for the partner
    - Add new trusted CA (upload certificate)
    - Enable/disable trusted CAs
    - Delete trusted CAs
    - View CA certificate details

    **Page Layout:**

    | Section | Description |
    |---------|-------------|
    | Header | "PIV Trusted Certificate Authorities" |
    | Grid | List of trusted CAs with columns: Subject, Issuer, Expiration, Enabled, Actions |
    | Add CA | File upload for new CA certificate |

    #### 11.3 PIV Device List Enhancement

    **File:** `SurePassIdLegacyMfaServer\devices.aspx` (MODIFY)

    **Changes:**
    - Add PIV-specific columns to device grid when filtering by PIV devices
    - Show certificate expiration warning icon
    - Show revocation status indicator
    - Add "PIV Certificates" filter option

    **New Grid Columns for PIV Devices:**

    | Column | Description |
    |--------|-------------|
    | Certificate Subject | CN from SubjectDN |
    | Key Slot | 9A, 9C, 9E |
    | Expires | NotAfter date with warning if < 30 days |
    | Revocation Status | Valid/Revoked/Unknown with icon |
    | Last Check | LastRevocationCheck timestamp |

    ---

    ### Phase 12: Bulk Certificate Import (.NET Framework 4.8)

    This phase adds the ability to import multiple PIV certificates from a CSV file, enabling efficient bulk enrollment for large deployments.

    #### 12.1 Import Pages

    **Files:**
    - `SurePassIdLegacyMfaServer\deviceimportpiv1.aspx` - File upload
    - `SurePassIdLegacyMfaServer\deviceimportpiv2.aspx` - Column mapping
    - `SurePassIdLegacyMfaServer\deviceimportpiv3.aspx` - Import options
    - `SurePassIdLegacyMfaServer\deviceimportpiv4.aspx` - Results

    #### 12.2 CSV File Format

    **Required Columns:**

    | Column | Type | Required | Description |
    |--------|------|----------|-------------|
    | `username` | string | Yes | User's login name (must exist) |
    | `certificate` | string | Yes | Base64-encoded DER certificate |
    | `deviceName` | string | No | Friendly name for the device |
    | `keySlot` | string | No | Key slot (9A, 9C, 9E). Auto-detected if omitted |

    **Example CSV:**

    ```csv
    username,certificate,deviceName,keySlot
    john.doe,MIIEpDCCA4ygAwIBAgIJ...,John's PIV Card,9A
    jane.smith,MIIEqDCCA5CgAwIBAgIK...,Jane's PIV Card,9A
    bob.wilson,MIIErDCCA5SgAwIBAgIM...,Bob's PIV Card,9E
    ```

    #### 12.3 Import Options Page

    **File:** `SurePassIdLegacyMfaServer\deviceimportpiv3.aspx` (NEW)

    **Import Options:**

    | Option | Type | Default | Description |
    |--------|------|---------|-------------|
    | Validate Certificate Chain | checkbox | ? | Validate against trusted CAs |
    | Check Revocation Status | checkbox | ? | Check CRL/OCSP during import |
    | Require FIPS 201 Policy | checkbox | ? | Require PIV policy OIDs |
    | Skip Duplicate Certificates | checkbox | ? | Skip if cert already enrolled |
    | Device Status | dropdown | Enabled | Initial device status |
    | Import Comments | text | | Batch notes for audit |

    #### 12.4 Import Processing

    **File:** `SurePassIdLegacyMfaServer\deviceimportpiv3.aspx.cs` (NEW)

    ```csharp
    public class ImportPivCertificateResult
    {
        public int TotalRecords { get; set; }
        public int SuccessCount { get; set; }
        public int ErrorCount { get; set; }
        public int SkippedCount { get; set; }
        public List<ImportPivCertificateError> Errors { get; set; }
    }

    public class ImportPivCertificateError
    {
        public int RowNumber { get; set; }
        public string Username { get; set; }
        public string ErrorCode { get; set; }
        public string ErrorMessage { get; set; }
    }

    protected ImportPivCertificateResult ProcessImport(
        Connection conn,
        List<ImportPivCertificateRow> rows,
        ImportPivCertificateOptions options)
    {
        var result = new ImportPivCertificateResult
        {
            TotalRecords = rows.Count,
            Errors = new List<ImportPivCertificateError>()
        };
    
        var pivCertService = new PivCertificateService();
        var revocationService = new PivRevocationService();
        var interfacePivCert = new InterfaceDevicePivCertificate();
        var interfacePartnerUser = new InterfacePartnerUser();
        var interfaceDevice = new InterfaceDevice();
    
        var trustedCAs = options.ValidateChain 
            ? GetTrustedCAs(conn, m_ospSession.PartnerId) 
            : null;
    
        for (int i = 0; i < rows.Count; i++)
        {
            var row = rows[i];
            try
            {
                // 1. Find user
                var user = interfacePartnerUser.FindPartnerUser(
                    conn, m_ospSession.PartnerId, row.Username, null);
                if (user == null)
                {
                    result.Errors.Add(new ImportPivCertificateError
                    {
                        RowNumber = i + 1,
                        Username = row.Username,
                        ErrorCode = "USER_NOT_FOUND",
                        ErrorMessage = "User not found"
                    });
                    result.ErrorCount++;
                    continue;
                }
            
                // 2. Parse certificate
                var certBytes = Convert.FromBase64String(row.CertificateBase64);
                var certInfo = pivCertService.ParseCertificate(certBytes);
            
                // 3. Check for duplicates
                if (options.SkipDuplicates)
                {
                    var existing = interfacePivCert.GetByCertificateHash(
                        conn, m_ospSession.PartnerId, certInfo.CertificateHash);
                    if (existing != null)
                    {
                        result.SkippedCount++;
                        continue;
                    }
                }
            
                // 4. Validate certificate chain
                if (options.ValidateChain)
                {
                    var cert = new X509Certificate2(certBytes);
                    var validationResult = pivCertService.ValidateCertificateChain(cert, trustedCAs);
                    if (!validationResult.IsValid)
                    {
                        result.Errors.Add(new ImportPivCertificateError
                        {
                            RowNumber = i + 1,
                            Username = row.Username,
                            ErrorCode = "CHAIN_INVALID",
                            ErrorMessage = validationResult.ErrorMessage
                        });
                        result.ErrorCount++;
                        continue;
                    }
                }
            
                // 5. Check FIPS 201 policy
                if (options.RequireFips201Policy)
                {
                    var cert = new X509Certificate2(certBytes);
                    if (!pivCertService.ValidatePivPolicy(cert))
                    {
                        result.Errors.Add(new ImportPivCertificateError
                        {
                            RowNumber = i + 1,
                            Username = row.Username,
                            ErrorCode = "POLICY_INVALID",
                            ErrorMessage = "Certificate does not contain required PIV policy OIDs"
                        });
                        result.ErrorCount++;
                        continue;
                    }
                }
            
                // 6. Check revocation (optional)
                var revocationStatus = RevocationStatus.Unknown;
                if (options.CheckRevocation)
                {
                    try
                    {
                        var cert = new X509Certificate2(certBytes);
                        var issuer = FindIssuerCertificate(conn, certInfo.IssuerDN);
                        if (issuer != null)
                        {
                            var revResult = revocationService.CheckRevocationStatusAsync(
                                cert, issuer, RevocationCheckMode.Online).Result;
                            revocationStatus = revResult.Status;
                        
                            if (revocationStatus == RevocationStatus.Revoked)
                            {
                                result.Errors.Add(new ImportPivCertificateError
                                {
                                    RowNumber = i + 1,
                                    Username = row.Username,
                                    ErrorCode = "CERT_REVOKED",
                                    ErrorMessage = "Certificate has been revoked"
                                });
                                result.ErrorCount++;
                                continue;
                            }
                        }
                    }
                    catch (Exception)
                    {
                        // Log warning, continue with Unknown status
                        revocationStatus = RevocationStatus.CheckFailed;
                    }
                }
            
                // 7. Create device and certificate records
                var device = interfaceDevice.CreateDefaultDevice(
                    conn,
                    m_ospSession.KeyManager,
                    m_ospSession.PartnerId,
                    user.Id,
                    -1,
                    (short)DeviceTypesEnum.PivSmartCard,
                    (short)OTPTypesEnum.PIV_Auth,
                    0, 0, null, null, null, null, null,
                    (short)options.DeviceStatus,
                    0,
                    MobileUsage.DEFAULT_NONE,
                    string.Empty,
                    row.DeviceName ?? $"PIV-{certInfo.SerialNumber.Substring(0, 8)}");
            
                var pivCert = new TableDevicePivCertificate
                {
                    DeviceId = device.Id,
                    PartnerId = m_ospSession.PartnerId,
                    Certificate = certBytes,
                    CertificateHash = certInfo.CertificateHash,
                    SubjectDN = certInfo.SubjectDN,
                    IssuerDN = certInfo.IssuerDN,
                    SerialNumber = certInfo.SerialNumber,
                    NotBefore = certInfo.NotBefore,
                    NotAfter = certInfo.NotAfter,
                    KeyUsage = (int)(row.KeySlot ?? certInfo.KeySlot),
                    FascN = certInfo.FascN,
                    Uuid = certInfo.Uuid,
                    RevocationStatus = (int)revocationStatus,
                    LastRevocationCheck = options.CheckRevocation ? DateTime.UtcNow : (DateTime?)null,
                    CreatedDate = DateTime.UtcNow
                };
            
                interfacePivCert.Add(conn, pivCert);
                result.SuccessCount++;
            }
            catch (Exception ex)
            {
                result.Errors.Add(new ImportPivCertificateError
                {
                    RowNumber = i + 1,
                    Username = row.Username,
                    ErrorCode = "UNEXPECTED_ERROR",
                    ErrorMessage = ex.Message
                });
                result.ErrorCount++;
            }
        }
    
        return result;
    }
    ```

    #### 12.5 Import Results Page

    **File:** `SurePassIdLegacyMfaServer\deviceimportpiv4.aspx` (NEW)

    **Display:**
    - Import summary (total, success, errors, skipped)
    - Error details grid with row number, username, error code, message
    - Export errors to CSV button
        - Link to imported devices

    ---

    ### Phase 13: Web Server Header-Based Authentication (.NET Framework 4.8)

    This phase adds support for PIV authentication when TLS client certificate validation is performed by the web server (IIS or NGINX) and certificate information is passed to the MFA server via HTTP headers.

    #### 13.1 New API: PIV Header Authentication

    **File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivHeaderAuth.cs` (NEW)

    **API Specification:**

    | Property | Value |
    |----------|-------|
    | **Type** | `piv_header_auth` |
    | **Permission** | `PivAuth` (55) |
    | **Purpose** | Authenticate using certificate info from web server headers |

    **Request Parameters:**

    | Parameter | Type | Required | Description |
    |-----------|------|----------|-------------|
    | `type` | string | Yes | `"piv_header_auth"` |
    | `spAccountLoginName` | string | Yes | API Key ID |
    | `spAccountLoginKey` | string | Yes | API Key Secret |
    | `username` | string | No | User's login name (if known) |
    | `certificateFingerprint` | string | No | SHA-256 fingerprint from header |
    | `certificateSubject` | string | No | Subject DN from header |
    | `certificateSerial` | string | No | Serial number from header |
    | `certificate` | string | No | Full certificate from header (Base64) |
    | `sessionTokenDurationMinutes` | int | No | Session token duration (default: 30) |

    **Request Example:**

    ```json
    {
        "type": "piv_header_auth",
        "spAccountLoginName": "api-key-id",
        "spAccountLoginKey": "api-key-secret",
        "certificateFingerprint": "A1B2C3D4E5F6...",
        "certificateSubject": "CN=John Doe, OU=Agency, O=Government, C=US"
    }
    ```

    **Success Response:**

    ```json
    {
        "type": "piv_header_auth",
        "errorCode": 0,
        "errorMessage": "OK",
        "sessionToken": "generated-session-token",
        "username": "john.doe",
        "certificateSubject": "CN=John Doe, OU=Agency, O=Government, C=US",
        "keySlot": "9A"
    }
    ```

    #### 13.2 Header Extraction Utility

    **File:** `SurePassIdLegacyMfaServer\server\PivHeaderExtractor.cs` (NEW)

    ```csharp
    namespace SurePassAdmin.server
    {
        /// <summary>
        /// Extracts PIV certificate information from HTTP headers set by IIS or NGINX
        /// </summary>
        public class PivHeaderExtractor
        {
            // Configurable header names
            public static class HeaderNames
            {
                // NGINX-style headers
                public const string ClientCert = "X-Client-Cert";
                public const string ClientCertSubject = "X-Client-Cert-Subject";
                public const string ClientCertIssuer = "X-Client-Cert-Issuer";
                public const string ClientCertSerial = "X-Client-Cert-Serial";
                public const string ClientCertFingerprint = "X-Client-Cert-Fingerprint";
                public const string ClientCertVerify = "X-Client-Cert-Verify";
                public const string ClientCertValidFrom = "X-Client-Cert-Valid-From";
                public const string ClientCertValidTo = "X-Client-Cert-Valid-To";
            
                // IIS-style headers (server variables)
                public const string SslClientCert = "SSL_CLIENT_CERT";
                public const string SslClientSubjectDn = "SSL_CLIENT_S_DN";
                public const string SslClientIssuerDn = "SSL_CLIENT_I_DN";
                public const string SslClientSerial = "SSL_CLIENT_M_SERIAL";
                public const string SslClientVerify = "SSL_CLIENT_VERIFY";
            }
        
            /// <summary>
            /// Extract certificate info from request headers
            /// </summary>
            public PivHeaderCertificateInfo ExtractFromHeaders(HttpRequest request)
            {
                var info = new PivHeaderCertificateInfo();
            
                // Try NGINX-style headers first
                info.Certificate = GetHeader(request, HeaderNames.ClientCert);
                info.SubjectDN = GetHeader(request, HeaderNames.ClientCertSubject);
                info.IssuerDN = GetHeader(request, HeaderNames.ClientCertIssuer);
                info.SerialNumber = GetHeader(request, HeaderNames.ClientCertSerial);
                info.Fingerprint = GetHeader(request, HeaderNames.ClientCertFingerprint);
                info.VerifyResult = GetHeader(request, HeaderNames.ClientCertVerify);
            
                // Fall back to IIS-style if NGINX headers not present
                if (string.IsNullOrEmpty(info.SubjectDN))
                {
                    info.Certificate = GetServerVariable(request, HeaderNames.SslClientCert);
                    info.SubjectDN = GetServerVariable(request, HeaderNames.SslClientSubjectDn);
                    info.IssuerDN = GetServerVariable(request, HeaderNames.SslClientIssuerDn);
                    info.SerialNumber = GetServerVariable(request, HeaderNames.SslClientSerial);
                    info.VerifyResult = GetServerVariable(request, HeaderNames.SslClientVerify);
                }
            
                // Calculate fingerprint from certificate if not provided
                if (string.IsNullOrEmpty(info.Fingerprint) && !string.IsNullOrEmpty(info.Certificate))
                {
                    info.Fingerprint = CalculateFingerprint(info.Certificate);
                }
            
                info.HasCertificateInfo = !string.IsNullOrEmpty(info.SubjectDN) || 
                                           !string.IsNullOrEmpty(info.Fingerprint);
            
                return info;
            }
        
            /// <summary>
            /// Validate that web server verified the certificate successfully
            /// </summary>
            public bool IsWebServerVerified(PivHeaderCertificateInfo info)
            {
                if (string.IsNullOrEmpty(info.VerifyResult))
                    return false;
                
                // NGINX returns "SUCCESS" on valid cert
                // IIS returns empty or specific values
                return info.VerifyResult.Equals("SUCCESS", StringComparison.OrdinalIgnoreCase) ||
                       info.VerifyResult.Equals("OK", StringComparison.OrdinalIgnoreCase) ||
                       info.VerifyResult.Equals("0", StringComparison.OrdinalIgnoreCase);
            }
        
            private string GetHeader(HttpRequest request, string headerName)
            {
                return request.Headers[headerName];
            }
        
            private string GetServerVariable(HttpRequest request, string variableName)
            {
                return request.ServerVariables[variableName];
            }
        
            private string CalculateFingerprint(string certificateBase64)
            {
                try
                {
                    // Handle URL-encoded certificates from NGINX
                    var certData = Uri.UnescapeDataString(certificateBase64);
                    var certBytes = Convert.FromBase64String(certData);
                
                    using (var sha256 = SHA256.Create())
                    {
                        var hash = sha256.ComputeHash(certBytes);
                        return BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
                    }
                }
                catch
                {
                    return null;
                }
            }
        }
    
        public class PivHeaderCertificateInfo
        {
            public string Certificate { get; set; }
            public string SubjectDN { get; set; }
            public string IssuerDN { get; set; }
            public string SerialNumber { get; set; }
            public string Fingerprint { get; set; }
            public string VerifyResult { get; set; }
            public bool HasCertificateInfo { get; set; }
        }
    }
    ```

    #### 13.3 API Action Implementation

    **File:** `SurePassIdLegacyMfaServer\server\ApiActions\PivHeaderAuth.cs` (NEW)

    ```csharp
    namespace SurePassAdmin.server.ApiActions
    {
        public class PivHeaderAuth : ApiAction, IApiAction
        {
            public bool Applies(string type)
            {
                return type.Equals(server_response.PIV_HEADER_AUTH, StringComparison.OrdinalIgnoreCase);
            }

            public object Execute(dynamic json, string username, spCommonPage sp, 
                TablePartner partner, bool trace, string serverAppId)
            {
                object response;
                var ipAddressData = sp.GetIpAddressData();
                var ipAddress = ipAddressData.ToString();
            
                // Extract certificate info from headers or JSON
                var headerExtractor = new PivHeaderExtractor();
                var headerInfo = headerExtractor.ExtractFromHeaders(sp.Request);
            
                // Override with JSON parameters if provided
                string certificateFingerprint = json["certificateFingerprint"]?.ToString() 
                    ?? headerInfo.Fingerprint;
                string certificateSubject = json["certificateSubject"]?.ToString() 
                    ?? headerInfo.SubjectDN;
                string certificateSerial = json["certificateSerial"]?.ToString() 
                    ?? headerInfo.SerialNumber;
                string certificate = json["certificate"]?.ToString() 
                    ?? headerInfo.Certificate;
            
                // Validate we have enough info to identify the certificate
                if (string.IsNullOrEmpty(certificateFingerprint) && 
                    string.IsNullOrEmpty(certificateSubject) &&
                    string.IsNullOrEmpty(certificate))
                {
                    response = FormatError(server_response.PIV_HEADER_AUTH, 
                        "No certificate information provided in headers or request", 
                        AuditResultCode.PivNoCertificatesEnrolled, trace);
                    return response;
                }
            
                // Optionally verify web server validation result
                if (SurePassConfiguration.PivRequireWebServerValidation)
                {
                    if (!headerExtractor.IsWebServerVerified(headerInfo))
                    {
                        response = FormatError(server_response.PIV_HEADER_AUTH,
                            $"Web server certificate validation failed: {headerInfo.VerifyResult}",
                            AuditResultCode.PivCertificateNotTrusted, trace);
                        return response;
                    }
                }

                try
                {
                    var conn = new Connection();
                    try
                    {
                        if (conn.Connect())
                        {
                            conn.OpenConnection();

                            var authServerApi = new AuthServerApi
                            {
                                IpAddressData = ipAddressData
                            };

                            var tPartner = authServerApi.IsApiRequestAuthorized(conn,
                                partner.AuthServerLoginName,
                                partner.AuthServerLoginPassword,
                                ApiPermissionsEnum.PivAuth,
                                AuditAction.PivAuth);

                            if (tPartner == null)
                            {
                                return FormatError(server_response.PIV_HEADER_AUTH, 
                                    authServerApi.ErrorMsg, 
                                    AuditResultCode.Find(authServerApi.ErrorCode.Code), trace);
                            }

                            // Look up enrolled certificate
                            var interfacePivCert = new InterfaceDevicePivCertificate();
                            TableDevicePivCertificate pivCert = null;
                        
                            // Try fingerprint first (most reliable)
                            if (!string.IsNullOrEmpty(certificateFingerprint))
                            {
                                pivCert = interfacePivCert.GetByCertificateHash(
                                    conn, tPartner.Id, certificateFingerprint);
                            }
                        
                            // Fall back to subject+serial lookup
                            if (pivCert == null && !string.IsNullOrEmpty(certificateSubject))
                            {
                                pivCert = interfacePivCert.GetBySubjectAndSerial(
                                    conn, tPartner.Id, certificateSubject, certificateSerial);
                            }
                        
                            if (pivCert == null)
                            {
                                return FormatError(server_response.PIV_HEADER_AUTH,
                                    "Certificate not enrolled",
                                    AuditResultCode.PivNoCertificatesEnrolled, trace);
                            }
                        
                            // Get associated device and user
                            var interfaceDevice = new InterfaceDevice();
                            var device = interfaceDevice.GetById(conn, pivCert.DeviceId);
                        
                            if (device == null || device.Status != (int)DeviceEnabledStatusEnum.Enabled)
                            {
                                return FormatError(server_response.PIV_HEADER_AUTH,
                                    "PIV device is disabled",
                                    AuditResultCode.DeviceDisabled, trace);
                            }
                        
                            // Check certificate expiration
                            if (pivCert.NotAfter < DateTime.UtcNow)
                            {
                                return FormatError(server_response.PIV_HEADER_AUTH,
                                    "Certificate has expired",
                                    AuditResultCode.PivCertificateExpired, trace);
                            }
                        
                            // Check revocation status (if cached check is enabled)
                            if (SurePassConfiguration.PivCheckCachedRevocationOnHeaderAuth)
                            {
                                if (pivCert.RevocationStatus == (int)RevocationStatus.Revoked)
                                {
                                    return FormatError(server_response.PIV_HEADER_AUTH,
                                        "Certificate has been revoked",
                                        AuditResultCode.PivCertificateRevoked, trace);
                                }
                            }
                        
                            // Get user info
                            var interfacePartnerUser = new InterfacePartnerUser();
                            var partnerUser = interfacePartnerUser.GetPartnerUser(
                                conn, device.AssignedPartnerUserId.Value);
                        
                            if (partnerUser == null)
                            {
                                return FormatError(server_response.PIV_HEADER_AUTH,
                                    "User not found for enrolled certificate",
                                    AuditResultCode.PartnerUserNotFound, trace);
                            }
                        
                            // Create session token
                            int tokenDuration = 30;
                            if (json["sessionTokenDurationMinutes"] != null)
                            {
                                tokenDuration = (int)json["sessionTokenDurationMinutes"];
                            }
                        
                            var sessionToken = authServerApi.CreateSessionToken(
                                conn, tPartner, partnerUser, tokenDuration);
                        
                            // Log successful authentication
                            AuditService.WriteAuditRecord(
                                AuditAction.PivAuth,
                                AuditResultCode.Success,
                                AuditSeverity.Success,
                                AuditType.ServerApi,
                                $"PIV Header Auth successful for user {partnerUser.LoginName}, " +
                                $"cert subject: {pivCert.SubjectDN}");
                        
                            response = new PivHeaderAuthResponse
                            {
                                Type = server_response.PIV_HEADER_AUTH,
                                ErrorCode = 0,
                                ErrorMessage = "OK",
                                SessionToken = sessionToken,
                                Username = partnerUser.LoginName,
                                CertificateSubject = pivCert.SubjectDN,
                                KeySlot = ((PivKeySlot)pivCert.KeyUsage).ToString()
                            };
                        }
                        else
                        {
                            response = FormatError(server_response.PIV_HEADER_AUTH, 
                                conn.GetLastError(), AuditResultCode.DatabaseError, trace);
                        }
                    }
                    finally
                    {
                        conn.CloseConnection();
                    }
                }
                catch (Exception ex)
                {
                    response = FormatError(server_response.PIV_HEADER_AUTH, 
                        ex.Message, AuditResultCode.DiagnosticTrace, trace);
                }
            
                return response;
            }
        }
    }
    ```

    #### 13.4 Configuration Parameters

    Add to Phase 8 configuration:

    | Parameter | Type | Default | Description |
    |-----------|------|---------|-------------|
    | `Piv.HeaderAuth.Enabled` | bool | false | Enable header-based PIV authentication |
    | `Piv.HeaderAuth.RequireWebServerValidation` | bool | true | Require web server to report successful validation |
    | `Piv.HeaderAuth.CheckCachedRevocation` | bool | true | Check cached revocation status on header auth |
    | `Piv.HeaderAuth.TrustedProxies` | string | "" | Comma-separated list of trusted proxy IPs |
    | `Piv.HeaderAuth.SubjectHeaderName` | string | "X-Client-Cert-Subject" | Configurable header name for subject |
    | `Piv.HeaderAuth.FingerprintHeaderName` | string | "X-Client-Cert-Fingerprint" | Configurable header name for fingerprint |

    **web.config:**

    ```xml
    <appSettings>
        <!-- Existing PIV settings -->
        <add key="Piv.Enabled" value="true" />
    
        <!-- Header-based authentication settings -->
        <add key="Piv.HeaderAuth.Enabled" value="true" />
        <add key="Piv.HeaderAuth.RequireWebServerValidation" value="true" />
        <add key="Piv.HeaderAuth.CheckCachedRevocation" value="true" />
        <add key="Piv.HeaderAuth.TrustedProxies" value="10.0.0.1,10.0.0.2" />
    </appSettings>
    ```

    #### 13.5 Security Considerations for Header-Based Auth

    | Concern | Mitigation |
    |---------|------------|
    | Header Spoofing | Only accept headers from trusted reverse proxies (validate `X-Forwarded-For`) |
    | Missing Validation | Require `X-Client-Cert-Verify: SUCCESS` header from web server |
    | Replay Attacks | Certificate fingerprint is tied to specific enrolled certificate |
    | Certificate Not Enrolled | Lookup by fingerprint must find matching enrolled certificate |
    | Revoked Certificate | Check cached revocation status; optionally trigger online check |

    #### 13.6 Deployment Architectures

    **Architecture 1: NGINX Reverse Proxy**

    ```
    ??????????????     ??????????????     ??????????????
    ?   Client   ???????   NGINX    ??????? MFA Server ?
    ? (PIV Card) ? TLS ?  (TLS      ?HTTP ? (IIS/      ?
    ?            ?     ?   Term)    ?     ?  Kestrel)  ?
    ??????????????     ??????????????     ??????????????
                       Validates cert     Receives headers:
                       Adds headers       X-Client-Cert-*
    ```

    **Architecture 2: IIS with Client Certificates**

    ```
    ??????????????     ??????????????????????????????????
    ?   Client   ???????           IIS Server            ?
    ? (PIV Card) ? TLS ?  ???????????????????????????   ?
    ?            ?     ?  ?   Client Cert Module    ?   ?
    ??????????????     ?  ?   (validates cert)      ?   ?
                       ?  ???????????????????????????   ?
                       ?              ?                  ?
                       ?  ???????????????????????????   ?
                       ?  ?   MFA Server App Pool   ?   ?
                       ?  ?   (receives server vars)?   ?
                       ?  ???????????????????????????   ?
                       ??????????????????????????????????
    ```

    **Architecture 3: Load Balancer with TLS Passthrough**

    ```
    ??????????????     ??????????????     ??????????????
    ?   Client   ???????    Load    ??????? MFA Server ?
    ? (PIV Card) ? TLS ?  Balancer  ? TLS ? (handles   ?
    ?            ?     ? (passthru) ?     ?  TLS+cert) ?
    ??????????????     ??????????????     ??????????????
                       No headers added   Uses challenge-
                                          response flow
    ```
```

---

## API Reference

### PIV APIs Summary

| API Type | Permission | Description |
|----------|------------|-------------|
| `piv_pre_enroll` | PivEnroll (54) | Initiate PIV certificate enrollment |
| `piv_enroll` | PivEnroll (54) | Complete PIV certificate enrollment |
| `piv_pre_auth` | PivAuth (55) | Initiate PIV authentication |
| `piv_auth` | PivAuth (55) | Complete PIV authentication |
| `piv_header_auth` | PivAuth (55) | Authenticate via web server headers (IIS/NGINX) |
| `piv_find_device` | PivFind (57) | Find PIV device/certificate |
| `piv_delete_device` | PivDelete (56) | Delete PIV device/certificate |

### Permission Requirements

| Permission ID | Permission Name | APIs |
|---------------|-----------------|------|
| 54 | PivEnroll | `piv_pre_enroll`, `piv_enroll` |
| 55 | PivAuth | `piv_pre_auth`, `piv_auth` |
| 56 | PivDelete | `piv_delete_device` |
| 57 | PivFind | `piv_find_device` |
| 58 | PivRevocationCheck | (internal use) |

---

## Database Schema

### DevicePivCertificate Table

```sql
CREATE TABLE [dbo].[DevicePivCertificate] (
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Device Id] INT NOT NULL,
    [Partner Id] INT NOT NULL,
    [Certificate] VARBINARY(MAX) NOT NULL,
    [CertificateHash] VARCHAR(128) NOT NULL,
    [SubjectDN] NVARCHAR(500) NOT NULL,
    [IssuerDN] NVARCHAR(500) NOT NULL,
    [SerialNumber] VARCHAR(100) NOT NULL,
    [NotBefore] DATETIME NOT NULL,
    [NotAfter] DATETIME NOT NULL,
    [KeyUsage] INT NOT NULL,
    [FASC_N] VARCHAR(100) NULL,
    [UUID] VARCHAR(50) NULL,
    [RevocationStatus] INT NOT NULL DEFAULT 0,
    [LastRevocationCheck] DATETIME NULL,
    [Created Date] DATETIME NOT NULL DEFAULT GETDATE(),
    [Last Update Date] DATETIME NULL,
    
    CONSTRAINT [FK_DevicePivCertificate_Device] 
        FOREIGN KEY ([Device Id]) REFERENCES [Device]([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_DevicePivCertificate_Partner] 
        FOREIGN KEY ([Partner Id]) REFERENCES [Partner]([Id])
);

CREATE UNIQUE INDEX [IX_DevicePivCertificate_Hash] 
    ON [DevicePivCertificate]([Partner Id], [CertificateHash]);
CREATE INDEX [IX_DevicePivCertificate_DeviceId] 
    ON [DevicePivCertificate]([Device Id]);
CREATE INDEX [IX_DevicePivCertificate_Expiration] 
    ON [DevicePivCertificate]([NotAfter]);
```

### PivTrustedCA Table

```sql
CREATE TABLE [dbo].[PivTrustedCA] (
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Partner Id] INT NOT NULL,
    [Certificate] VARBINARY(MAX) NOT NULL,
    [SubjectDN] NVARCHAR(500) NOT NULL,
    [CertificateHash] VARCHAR(128) NOT NULL,
    [IsRoot] BIT NOT NULL DEFAULT 0,
    [CrlDistributionPoint] NVARCHAR(500) NULL,
    [OcspResponder] NVARCHAR(500) NULL,
    [Enabled] BIT NOT NULL DEFAULT 1,
    [Created Date] DATETIME NOT NULL DEFAULT GETDATE(),
    
    CONSTRAINT [FK_PivTrustedCA_Partner] 
        FOREIGN KEY ([Partner Id]) REFERENCES [Partner]([Id])
);

CREATE UNIQUE INDEX [IX_PivTrustedCA_Hash] 
    ON [PivTrustedCA]([Partner Id], [CertificateHash]);
```

### PivAuthSession Table

```sql
CREATE TABLE [dbo].[PivAuthSession] (
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Partner Id] INT NOT NULL,
    [Partner User Id] INT NULL,
    [SessionId] VARCHAR(64) NOT NULL,
    [Challenge] VARBINARY(64) NOT NULL,
    [CertificateHash] VARCHAR(128) NULL,
    [State] INT NOT NULL DEFAULT 0,
    [Created Date] DATETIME NOT NULL DEFAULT GETDATE(),
    [Expiration Date] DATETIME NOT NULL,
    
    CONSTRAINT [FK_PivAuthSession_Partner] 
        FOREIGN KEY ([Partner Id]) REFERENCES [Partner]([Id]),
    CONSTRAINT [FK_PivAuthSession_PartnerUser] 
        FOREIGN KEY ([Partner User Id]) REFERENCES [PartnerUser]([Id])
);

CREATE UNIQUE INDEX [IX_PivAuthSession_SessionId] 
    ON [PivAuthSession]([SessionId]);
CREATE INDEX [IX_PivAuthSession_Expiration] 
    ON [PivAuthSession]([Expiration Date]);
```

### ApiPermission Updates

```sql
-- Add PIV permissions
INSERT INTO [dbo].[ApiPermission] VALUES
(54, 'PivEnroll', 'PIV Authentication', 0),
(55, 'PivAuth', 'PIV Authentication', 0),
(56, 'PivDelete', 'PIV Authentication', 0),
(57, 'PivFind', 'PIV Authentication', 0),
(58, 'PivRevocationCheck', 'PIV Authentication', 0);

-- Add API endpoints
INSERT INTO [dbo].[ApiEndpoint] VALUES
(54, 'piv_pre_enroll'),
(54, 'piv_enroll'),
(55, 'piv_pre_auth'),
(55, 'piv_auth'),
(56, 'piv_delete_device'),
(57, 'piv_find_device');
```

---

## Security Considerations

### Private Key Protection

- Private keys **never leave the PIV card**
- Only public certificates are stored server-side
- Challenge signing happens entirely on the card
- PIN entry is handled by the card/middleware, not the server

### Challenge Security

- Challenges use cryptographically random 32-byte nonces
- Challenges expire after configurable timeout (default: 5 minutes)
- Each challenge can only be used once
- Challenges are bound to specific sessions

### Replay Protection

- Session IDs are unique and unpredictable
- Signed challenges include session binding
- Completed sessions are marked and cannot be reused

### Certificate Validation

- Full certificate chain validation against trusted CAs
- Real-time or cached revocation checking (CRL/OCSP)
- Policy OID validation for FIPS 201 compliance
- Key usage validation for appropriate PIV key slot

### FIPS Compliance

- Use FIPS-validated cryptographic providers on .NET Framework 4.8
- Support FIPS 201-approved algorithms (RSA-2048+, ECDSA P-256/P-384)
- Validate PIV policy OIDs when `Piv.RequireFips201Policy` is enabled

---

## Testing Requirements

### Unit Tests

| Test Category | Description |
|---------------|-------------|
| Certificate Parsing | Parse valid/invalid X.509 certificates |
| Chain Validation | Validate certificate chains with various scenarios |
| Signature Verification | Verify RSA and ECDSA signatures |
| Challenge Generation | Verify challenge randomness and uniqueness |
| Session Management | Test session creation, expiration, cleanup |

### Integration Tests

| Test Scenario | Description |
|---------------|-------------|
| Full Enrollment Flow | Complete PIV enrollment from pre-enroll to completion |
| Full Authentication Flow | Complete PIV authentication flow |
| Multi-Certificate User | User with multiple PIV certificates |
| Certificate Expiration | Handle expired certificate scenarios |
| Certificate Revocation | Handle revoked certificate scenarios |
| Session Timeout | Verify session expiration handling |

### Compatibility Tests

| Test Target | Description |
|-------------|-------------|
| PIV Card Vendors | Test with cards from multiple vendors |
| Middleware | Test with different PKCS#11 middleware |
| Browsers | Test Web Crypto API across browsers |
| Operating Systems | Test on Windows, macOS, Linux |

### Security Tests

| Test Case | Description |
|-----------|-------------|
| Invalid Certificate | Reject malformed certificates |
| Expired Certificate | Reject expired certificates |
| Revoked Certificate | Reject revoked certificates |
| Untrusted CA | Reject certificates from untrusted CAs |
| Wrong Key Slot | Reject certificates from disallowed key slots |
| Replay Attack | Prevent challenge replay |
| Session Hijacking | Prevent session takeover |

---

## Implementation Timeline

| Phase | Location | Framework | Priority | Effort | Dependencies |
|-------|----------|-----------|----------|--------|--------------|
| Phase 1: Data Model & Enumerations | `SurePassIdDotNetStdLib` | .NET Standard 2.0 | P0 | 1 week | None |
| Phase 2: Core PIV Infrastructure | `SurePassIdDotNetStdLib` | .NET Standard 2.0 | P0 | 2 weeks | Phase 1 |
| Phase 3: Database Repository Interfaces | `SurePassIdDotNetStdLib` | .NET Standard 2.0 | P0 | 3 days | Phase 1 |
| Phase 3b: Database Repository Implementations | `SurePassClassLib` | .NET Framework 4.8 | P0 | 4 days | Phase 3 |
| Phase 4: REST API Endpoints | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P0 | 2 weeks | Phases 2, 3b |
| Phase 5: API Type Constants | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P0 | 1 day | Phase 4 |
| Phase 6: Integration with Existing APIs | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P1 | 1 week | Phase 4 |
| Phase 7: Error Codes | `SurePassClassLib` | .NET Framework 4.8 | P1 | 2 days | Phase 4 |
| Phase 8: Configuration | Mixed | Mixed | P1 | 2 days | Phase 2 |
| Phase 9: Audit Logging | `SurePassClassLib` | .NET Framework 4.8 | P1 | 3 days | Phase 4 |
| Phase 10: Client-Side Integration | N/A | N/A | P1 | 1 week | Phase 4 |
| Phase 11: Admin UI Integration | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P1 | 1.5 weeks | Phases 2, 3b, 4 |
| Phase 12: Bulk Certificate Import | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P2 | 1 week | Phases 2, 3b, 11 |
| Phase 13: Header-Based Auth (IIS/NGINX) | `SurePassIdLegacyMfaServer` | .NET Framework 4.8 | P1 | 1 week | Phases 3b, 4 |

**Total Estimated Timeline:** 11-13 weeks

### Milestone Schedule

| Milestone | Target Date | Deliverables |
|-----------|-------------|--------------|
| M1: Foundation | Week 2 | Data model, enumerations, repository interfaces in .NET Standard 2.0 |
| M2: Core Services | Week 4 | Certificate, revocation, challenge services in .NET Standard 2.0 |
| M3: Database Layer | Week 5 | Repository implementations in .NET Framework 4.8 |
| M4: REST APIs | Week 7 | All PIV REST API endpoints in .NET Framework 4.8 |
| M5: Integration | Week 9 | Integration with existing APIs, audit logging |
| M6: Admin UI | Week 10.5 | Admin console PIV management, trusted CA management |
| M7: Bulk Import | Week 11.5 | CSV import functionality |
| M8: Header Auth | Week 12.5 | IIS/NGINX header-based authentication |
| M9: Documentation | Week 13 | Client documentation, test results |

### Enrollment Method Availability by Phase

| Enrollment Method | Available After | APIs/UI Components |
|-------------------|-----------------|-------------------|
| Self-Service (REST API) | Phase 4 | `piv_pre_enroll`, `piv_enroll` |
| Admin Manual (UI) | Phase 11 | `devicedetail.aspx` with PIV support |
| Bulk Import (CSV) | Phase 12 | `deviceimportpiv*.aspx` pages |
| API Direct (no challenge) | Phase 4 (extended) | `piv_enroll` with `skipChallenge=true` |

### Authentication Method Availability by Phase

| Authentication Method | Available After | APIs/Components |
|----------------------|-----------------|-----------------|
| REST API Challenge-Response | Phase 4 | `piv_pre_auth`, `piv_auth` |
| VPN/RADIUS Integration | Phase 6 | RADIUS server integration |
| SAML2 SSO | Phase 6 | SAML2 IdP integration |
| Header-Based (IIS/NGINX) | Phase 13 | `piv_header_auth` API |
| Admin UI Login | Phase 11 | Login page PIV option |

---

## Appendix A: PIV Policy OIDs

### Common PIV Policy OIDs

| OID | Name | Description |
|-----|------|-------------|
| 2.16.840.1.101.3.2.1.3.13 | id-fpki-common-authentication | Common authentication policy |
| 2.16.840.1.101.3.2.1.3.16 | id-fpki-common-high | High assurance policy |
| 2.16.840.1.101.3.2.1.3.7 | id-fpki-common-hardware | Hardware-protected key |
| 2.16.840.1.101.3.2.1.3.6 | id-fpki-common-policy | Common policy |

---

## Appendix B: References

- [FIPS 201-3](https://csrc.nist.gov/publications/detail/fips/201/3/final) - Personal Identity Verification (PIV) of Federal Employees and Contractors
- [SP 800-73-4](https://csrc.nist.gov/publications/detail/sp/800-73/4/final) - Interfaces for Personal Identity Verification
- [SP 800-76-2](https://csrc.nist.gov/publications/detail/sp/800-76/2/final) - Biometric Specifications for Personal Identity Verification
- [RFC 5280](https://tools.ietf.org/html/rfc5280) - Internet X.509 PKI Certificate and CRL Profile
- [RFC 6960](https://tools.ietf.org/html/rfc6960) - Online Certificate Status Protocol (OCSP)

---

*Document generated for SurePassID Authentication Services*  
*PIV Smart Card Authentication Feature Implementation*
