Project 4: 3D Secure Authentication Flow

Goal: Build practical expertise in payment security by implementing core controls (validation, tokenization, encryption), understanding PCI scope, and producing auditable, compliant artifacts.

Payment Data Boundaries

Payment systems live or die by data boundaries: where PANs can exist, how they move, and who can touch them. You need to draw a clear boundary between the Cardholder Data Environment (CDE) and everything else to reduce scope and risk.

Cryptographic Controls and Key Management

Payments rely on strong symmetric encryption, deterministic tokenization, and strict key lifecycle controls. Key custody, rotation, and HSM-backed operations are as important as the algorithms themselves.

Transaction Flow and Compliance Guarantees

Authorization, capture, and settlement have different security requirements. Compliance (PCI DSS, PCI PIN, 3DS) enforces minimal guarantees that must be reflected in system design.

Concept Summary Table

Concept Cluster What You Need to Internalize
Data classification PAN vs token, CDE boundaries, data minimization.
Cryptography AES, KDFs, tokenization, key hierarchy.
Transaction security Auth vs settlement, 3DS, P2PE.
Compliance PCI DSS scope, audit controls, evidence.
Risk controls Rate limits, fraud signals, logging.

Deep Dive Reading by Concept

Concept Book & Chapter
PCI DSS PCI DSS v4.0 — Requirements overview
Tokenization PCI Tokenization Guidelines — Implementation sections
Crypto in payments Cryptography Engineering — Ch. 6-9
Payment flows Payment Systems in the U.S. — transaction chapters
Fraud controls The Anatomy of the Payment Card Industry — risk sections

Project Overview

Attribute Value
Difficulty Level 3: Advanced
Time Estimate 2 weeks
Programming Language C / Web (HTML/JS for frontend simulation)
Knowledge Area Payment Protocols / Authentication
Key Technologies 3D Secure 2.0, EMVCo Specs, Digital Signatures
Coolness Level Level 3: Genuinely Clever
Business Potential 3. The “Service & Support” Model

Learning Objectives

By completing this project, you will:

  1. Understand the 3D Secure protocol - Learn how cardholder authentication works for online payments
  2. Implement the three-party model - Build merchant, issuer, and directory server components
  3. Handle challenge and frictionless flows - Implement risk-based authentication decisions
  4. Verify cryptographic assertions - Validate signatures between parties
  5. Manage redirect flows securely - Prevent session hijacking and CSRF
  6. Understand liability shift - Learn how authentication affects fraud liability

The Core Question You’re Answering

“How can a bank verify that the person making an online purchase actually owns the card?”

Unlike in-store transactions where you physically present the card, online transactions have no way to verify cardholder presence. 3D Secure solves this:

┌─────────────────────────────────────────────────────────────────────────┐
│                    THE CARD-NOT-PRESENT PROBLEM                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  IN-STORE TRANSACTION                  ONLINE TRANSACTION                │
│  ════════════════════                  ══════════════════                │
│                                                                          │
│  ┌──────────────┐                      ┌──────────────┐                 │
│  │   Customer   │                      │   Customer   │                 │
│  │   with card  │                      │   (remote)   │                 │
│  └──────┬───────┘                      └──────┬───────┘                 │
│         │                                     │                          │
│         │ Presents card                       │ Types card number        │
│         │ Enters PIN                          │ ...that's it?           │
│         │ Signs receipt                       │                          │
│         ▼                                     ▼                          │
│  ┌──────────────┐                      ┌──────────────┐                 │
│  │   Terminal   │                      │   Website    │                 │
│  │   verifies:  │                      │   has:       │                 │
│  │   • Card     │                      │   • PAN      │                 │
│  │   • PIN      │                      │   • CVV      │                 │
│  │   • Chip     │                      │   • Expiry   │                 │
│  │   • Signature│                      │              │                 │
│  └──────────────┘                      └──────────────┘                 │
│                                                                          │
│  Authentication: Strong                Authentication: WEAK!             │
│  (something you have +                 (something you know +             │
│   something you know)                   ...nothing else)                 │
│                                                                          │
│  ─────────────────────────────────────────────────────────────────────   │
│                                                                          │
│  3D SECURE ADDS:                                                         │
│  ═══════════════                                                         │
│                                                                          │
│  ┌──────────────┐      ┌──────────────┐      ┌──────────────┐          │
│  │   Customer   │      │   Merchant   │      │   Issuer     │          │
│  │              │◄────►│   (website)  │◄────►│   (bank)     │          │
│  └──────────────┘      └──────────────┘      └──────────────┘          │
│         │                                           │                    │
│         │                                           │                    │
│         │         Challenge (if needed)             │                    │
│         └──────────────────────────────────────────►│                    │
│                   OTP, biometric, app notification  │                    │
│                                                                          │
│  Now the ISSUER verifies the cardholder!                                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

The Security Model: 3D Secure lets the card-issuing bank authenticate its own customer, rather than trusting the merchant.


Deep Theoretical Foundation

1. The Three Domains

“3D” refers to Three Domains:

┌─────────────────────────────────────────────────────────────────────────┐
│                        THREE DOMAIN MODEL                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  DOMAIN 1: ISSUER DOMAIN                                                 │
│  ═══════════════════════                                                 │
│  • Card-issuing bank                                                     │
│  • Access Control Server (ACS)                                          │
│  • Authenticates the cardholder                                          │
│  • Example: Your bank (Chase, BofA, etc.)                               │
│                                                                          │
│  ─────────────────────────────────────────────────────────────────────   │
│                                                                          │
│  DOMAIN 2: ACQUIRER DOMAIN                                               │
│  ═════════════════════════                                               │
│  • Merchant's payment processor                                          │
│  • 3DS Server (MPI - Merchant Plug-In)                                  │
│  • Initiates authentication                                              │
│  • Example: Stripe, Square, Adyen                                        │
│                                                                          │
│  ─────────────────────────────────────────────────────────────────────   │
│                                                                          │
│  DOMAIN 3: INTEROPERABILITY DOMAIN                                       │
│  ═════════════════════════════════                                       │
│  • Card network infrastructure                                           │
│  • Directory Server (DS)                                                 │
│  • Routes messages between domains                                       │
│  • Example: Visa, Mastercard                                             │
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                                                                  │    │
│  │   ISSUER           INTEROPERABILITY           ACQUIRER          │    │
│  │   DOMAIN               DOMAIN                 DOMAIN            │    │
│  │                                                                  │    │
│  │   ┌───────┐         ┌───────┐            ┌───────────┐         │    │
│  │   │  ACS  │◄───────►│  DS   │◄──────────►│ 3DS Server│         │    │
│  │   │       │         │       │            │   (MPI)   │         │    │
│  │   └───┬───┘         └───────┘            └─────┬─────┘         │    │
│  │       │                                        │               │    │
│  │       │         Challenge Flow                 │               │    │
│  │       │◄──────────────────────────────────────►│               │    │
│  │       │                                        │               │    │
│  │   ┌───▼───┐                              ┌─────▼─────┐         │    │
│  │   │Issuer │                              │ Merchant  │         │    │
│  │   │ Bank  │                              │  Website  │         │    │
│  │   └───────┘                              └───────────┘         │    │
│  │                                                                  │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2. 3D Secure 2.0 vs 1.0

3D Secure 1.0 (Deprecated):

  • Every transaction required a redirect
  • Full-page redirect to bank’s authentication page
  • Poor mobile experience
  • High cart abandonment

3D Secure 2.0 (Current):

  • Risk-based authentication
  • Frictionless flow for low-risk transactions
  • Embedded challenge (iframe, not redirect)
  • Mobile SDK support
  • Better data sharing for risk decisions
┌─────────────────────────────────────────────────────────────────────────┐
│                    3DS 1.0 vs 3DS 2.0 FLOW                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  3DS 1.0 (old)                         3DS 2.0 (current)                │
│  ═════════════                         ═════════════════                 │
│                                                                          │
│  Every transaction:                    Risk assessment first:           │
│                                                                          │
│  Customer → Merchant → Redirect →      Customer → Merchant → DS →       │
│  Bank Page → Password → Redirect →     │                                │
│  Merchant                               ├─► Low risk? Frictionless      │
│                                        │    (no customer action)        │
│                                        │                                │
│                                        └─► High risk? Challenge         │
│                                             (OTP, biometric, etc.)      │
│                                                                          │
│  Friction: 100%                        Friction: ~5% (typical)          │
│  Abandonment: High                     Abandonment: Low                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3. The Authentication Request (AReq)

The merchant (via 3DS Server) sends rich data to the Directory Server:

┌─────────────────────────────────────────────────────────────────────────┐
│                    AUTHENTICATION REQUEST (AReq)                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  REQUIRED FIELDS:                                                        │
│  ════════════════                                                        │
│  • messageType: "AReq"                                                  │
│  • messageVersion: "2.2.0"                                              │
│  • threeDSServerTransID: unique transaction ID                          │
│  • acctNumber: PAN (encrypted)                                          │
│  • cardExpiryDate: "2512" (YYMM)                                        │
│  • purchaseAmount: "10000" (in minor units)                             │
│  • purchaseCurrency: "840" (USD)                                        │
│  • merchantName: "Example Store"                                        │
│  • deviceChannel: "02" (browser) / "01" (app)                          │
│                                                                          │
│  RISK ASSESSMENT DATA:                                                   │
│  ═════════════════════                                                   │
│  • browserAcceptHeader: from HTTP request                               │
│  • browserIP: customer's IP address                                      │
│  • browserLanguage: "en-US"                                             │
│  • browserUserAgent: full user agent string                             │
│  • browserJavaEnabled: true/false                                       │
│  • browserColorDepth: "24"                                              │
│  • browserScreenHeight: "1080"                                          │
│  • browserScreenWidth: "1920"                                           │
│  • browserTZ: "-300" (timezone offset)                                  │
│                                                                          │
│  • cardholderEmail: "customer@example.com"                              │
│  • cardholderName: "John Doe"                                           │
│  • billAddrLine1, billAddrCity, billAddrPostCode, billAddrCountry       │
│  • shipAddrLine1, shipAddrCity, shipAddrPostCode, shipAddrCountry       │
│                                                                          │
│  • threeDSRequestorAuthenticationInd: "01" (payment)                    │
│  • transType: "01" (goods/service purchase)                             │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4. Risk-Based Authentication

The ACS (issuer) analyzes the AReq data to decide:

┌─────────────────────────────────────────────────────────────────────────┐
│                    RISK-BASED DECISION MATRIX                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  SIGNALS FOR FRICTIONLESS (low risk):                                   │
│  ═══════════════════════════════════                                    │
│  • Known device (browser fingerprint matches history)                   │
│  • Known IP range (customer's usual location)                           │
│  • Low transaction amount                                                │
│  • Shipping to billing address                                          │
│  • Trusted merchant                                                      │
│  • Recent successful authentication                                      │
│                                                                          │
│  SIGNALS FOR CHALLENGE (high risk):                                     │
│  ═════════════════════════════════                                      │
│  • New device                                                            │
│  • Unusual location/IP                                                   │
│  • High transaction amount                                               │
│  • Different shipping address                                            │
│  • Unusual purchase time                                                 │
│  • Card recently compromised (data breach)                              │
│  • Multiple failed attempts                                              │
│                                                                          │
│  DECISION MATRIX:                                                        │
│  ═══════════════                                                         │
│                                                                          │
│          Low Amount │ High Amount                                        │
│         ────────────┼────────────                                        │
│  Known     │ ✓ Frictionless │ ? Maybe Challenge                          │
│  Device    │                │                                            │
│         ────────────┼────────────                                        │
│  New       │ ? Maybe       │ ✗ Challenge Required                        │
│  Device    │   Challenge   │                                             │
│         ────────────┼────────────                                        │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

5. Authentication Response (ARes)

┌─────────────────────────────────────────────────────────────────────────┐
│                    AUTHENTICATION RESPONSE (ARes)                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  FRICTIONLESS APPROVAL:                                                  │
│  ═════════════════════                                                   │
│  {                                                                       │
│    "messageType": "ARes",                                               │
│    "transStatus": "Y",              // Authenticated                    │
│    "transStatusReason": null,                                           │
│    "eci": "05",                     // Fully authenticated              │
│    "authenticationValue": "CAVV...", // Cryptographic proof            │
│    "acsTransID": "uuid"                                                 │
│  }                                                                       │
│                                                                          │
│  CHALLENGE REQUIRED:                                                     │
│  ══════════════════                                                      │
│  {                                                                       │
│    "messageType": "ARes",                                               │
│    "transStatus": "C",              // Challenge required               │
│    "acsChallengeMandated": "Y",                                         │
│    "acsURL": "https://acs.issuer.com/challenge",                       │
│    "acsTransID": "uuid",                                                │
│    "authenticationType": "01"        // OTP                             │
│  }                                                                       │
│                                                                          │
│  FAILED/REJECTED:                                                        │
│  ═══════════════                                                         │
│  {                                                                       │
│    "messageType": "ARes",                                               │
│    "transStatus": "N",              // Not authenticated                │
│    "transStatusReason": "01",       // Card not enrolled               │
│    "eci": "07"                      // Attempted (no liability shift)  │
│  }                                                                       │
│                                                                          │
│  TRANSACTION STATUS VALUES:                                              │
│  ══════════════════════════                                              │
│  Y = Authenticated                                                       │
│  N = Not authenticated / Authentication failed                          │
│  U = Authentication could not be performed                              │
│  A = Attempted (ACS not available)                                      │
│  C = Challenge required                                                  │
│  R = Rejected by issuer                                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6. ECI (E-Commerce Indicator) Values

┌─────────────────────────────────────────────────────────────────────────┐
│                           ECI VALUES                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  VISA:                                MASTERCARD:                       │
│  • 05: Fully authenticated            • 02: Fully authenticated         │
│  • 06: Attempted authentication       • 01: Attempted authentication    │
│  • 07: No authentication              • 00: No authentication           │
│                                                                          │
│  LIABILITY SHIFT:                                                        │
│  ════════════════                                                        │
│                                                                          │
│  ECI 05/02 (Authenticated):                                             │
│  • Liability shifts to ISSUER                                           │
│  • Merchant protected from chargebacks (fraud)                          │
│  • Best outcome for merchant                                             │
│                                                                          │
│  ECI 06/01 (Attempted):                                                 │
│  • Partial liability shift in some cases                                │
│  • Card enrolled but ACS unavailable                                    │
│                                                                          │
│  ECI 07/00 (No Authentication):                                         │
│  • No liability shift                                                    │
│  • Merchant bears fraud risk                                             │
│  • Card not enrolled or merchant opted out                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7. The Challenge Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                        CHALLENGE FLOW                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐       │
│  │ Customer │     │ Merchant │     │    DS    │     │   ACS    │       │
│  │ Browser  │     │   3DS    │     │          │     │ (Issuer) │       │
│  └────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘       │
│       │                │                │                │              │
│       │    Checkout    │                │                │              │
│       │───────────────►│                │                │              │
│       │                │     AReq       │                │              │
│       │                │───────────────►│                │              │
│       │                │                │     AReq       │              │
│       │                │                │───────────────►│              │
│       │                │                │                │              │
│       │                │                │     ARes       │              │
│       │                │                │◄───────────────│              │
│       │                │     ARes       │    (C=Challenge)              │
│       │                │◄───────────────│                │              │
│       │                │                │                │              │
│       │   Challenge    │                │                │              │
│       │   (iframe)     │                │                │              │
│       │◄───────────────│                │                │              │
│       │                │                │                │              │
│       ├──────────────────────────────────────────────────►              │
│       │                        CReq (challenge request)  │              │
│       │                                                  │              │
│       │◄──────────────────────────────────────────────────              │
│       │                        Challenge UI (OTP form)   │              │
│       │                                                  │              │
│       ├──────────────────────────────────────────────────►              │
│       │                        CRes (OTP entered)        │              │
│       │                                                  │              │
│       │◄──────────────────────────────────────────────────              │
│       │                        RReq (result)             │              │
│       │                │◄────────────────────────────────│              │
│       │                │                │                │              │
│       │    Result      │                │                │              │
│       │◄───────────────│                │                │              │
│       │                │                │                │              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Project Specification

What You’ll Build

A working 3D Secure 2.0 simulation including:

  1. Merchant 3DS Server: Initiates authentication
  2. Directory Server (Mock): Routes between merchant and issuer
  3. Access Control Server (Mock): Makes authentication decisions
  4. Checkout Page: Demonstrates the customer experience
  5. Challenge Interface: OTP/password challenge flow

Expected Output

╔═══════════════════════════════════════════════════════════════════════╗
║                    3D SECURE DEMO CHECKOUT                             ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                        ║
║  Purchase Details                                                      ║
║  ───────────────                                                       ║
║  Item: "Wireless Headphones"                                          ║
║  Amount: $149.99                                                       ║
║  Merchant: Demo Store                                                  ║
║                                                                        ║
║  Card Information                                                      ║
║  ───────────────                                                       ║
║  Card Number: 4111111111111111                                        ║
║  Expiry: 12/25                                                         ║
║  CVV: 123                                                              ║
║  Name: John Doe                                                        ║
║                                                                        ║
║  [PAY NOW]                                                             ║
║                                                                        ║
╚═══════════════════════════════════════════════════════════════════════╝

[User clicks PAY NOW]

╔═══════════════════════════════════════════════════════════════════════╗
║                    3DS AUTHENTICATION IN PROGRESS                      ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                        ║
║  [3DS Server] Collecting browser data...                              ║
║  [3DS Server] Browser: Chrome 121.0.0.0                               ║
║  [3DS Server] IP: 192.168.1.100                                       ║
║  [3DS Server] Screen: 1920x1080                                       ║
║                                                                        ║
║  [3DS Server] Sending AReq to Directory Server...                     ║
║  {                                                                     ║
║    "messageType": "AReq",                                             ║
║    "acctNumber": "4111111111111111",                                  ║
║    "purchaseAmount": "14999",                                         ║
║    "browserIP": "192.168.1.100"                                       ║
║  }                                                                     ║
║                                                                        ║
║  [DS] Received AReq, routing to ACS for BIN 411111...                 ║
║                                                                        ║
║  [ACS] Risk Assessment:                                                ║
║        • Known device: NO                                              ║
║        • Known IP: NO                                                  ║
║        • Amount: $149.99 (MEDIUM)                                     ║
║        • Risk Score: 72/100                                           ║
║        • Decision: CHALLENGE REQUIRED                                 ║
║                                                                        ║
║  [ACS] Sending ARes with transStatus="C"                              ║
║                                                                        ║
╚═══════════════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════════════╗
║                    CHALLENGE: Verify Your Identity                     ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                        ║
║  ┌─────────────────────────────────────────────────────────────────┐  ║
║  │                                                                  │  ║
║  │   🏦 Your Bank                                                   │  ║
║  │                                                                  │  ║
║  │   To verify this purchase, we've sent a one-time                │  ║
║  │   password to your registered phone ending in **89              │  ║
║  │                                                                  │  ║
║  │   Purchase: $149.99 at Demo Store                               │  ║
║  │                                                                  │  ║
║  │   Enter OTP: [______]                                           │  ║
║  │                                                                  │  ║
║  │   [VERIFY]   [Cancel]                                           │  ║
║  │                                                                  │  ║
║  │   Didn't receive code? Resend                                   │  ║
║  │                                                                  │  ║
║  └─────────────────────────────────────────────────────────────────┘  ║
║                                                                        ║
║  (This iframe is served by the issuer's ACS)                          ║
║                                                                        ║
╚═══════════════════════════════════════════════════════════════════════╝

[User enters correct OTP: 123456]

╔═══════════════════════════════════════════════════════════════════════╗
║                    AUTHENTICATION COMPLETE                             ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                        ║
║  [ACS] OTP verified successfully                                      ║
║  [ACS] Generating authentication value (CAVV)...                      ║
║  [ACS] Sending RReq to 3DS Server                                     ║
║                                                                        ║
║  Authentication Result:                                                ║
║  ─────────────────────                                                 ║
║  Status: Y (AUTHENTICATED)                                            ║
║  ECI: 05 (Visa fully authenticated)                                   ║
║  CAVV: AAABBJlHYWUZ... (base64)                                       ║
║                                                                        ║
║  LIABILITY SHIFT: ✓ Issuer accepts fraud liability                    ║
║                                                                        ║
║  [3DS Server] Authentication successful                                ║
║  [3DS Server] Proceeding with authorization...                        ║
║                                                                        ║
║  ═══════════════════════════════════════════════════════════════════  ║
║                                                                        ║
║                    ✓ PAYMENT APPROVED                                  ║
║                                                                        ║
║  Authorization Code: A12345                                            ║
║  Transaction ID: TXN-987654321                                        ║
║                                                                        ║
╚═══════════════════════════════════════════════════════════════════════╝

Project Structure

3ds_simulator/
├── src/
│   ├── main.c                      # CLI/server entry
│   ├── merchant/
│   │   ├── checkout.c              # Checkout page handler
│   │   ├── threeds_server.c        # 3DS Server (MPI)
│   │   └── browser_data.c          # Browser fingerprinting
│   ├── directory_server/
│   │   ├── ds.c                    # Directory Server
│   │   ├── routing.c               # BIN to ACS routing
│   │   └── message_validation.c    # Schema validation
│   ├── acs/
│   │   ├── acs.c                   # Access Control Server
│   │   ├── risk_engine.c           # Risk-based decision
│   │   ├── challenge.c             # Challenge flow
│   │   └── otp.c                   # OTP generation/validation
│   ├── protocol/
│   │   ├── areq.c                  # AReq message
│   │   ├── ares.c                  # ARes message
│   │   ├── creq.c                  # CReq message
│   │   ├── cres.c                  # CRes message
│   │   └── rreq.c                  # RReq message
│   ├── crypto/
│   │   ├── signatures.c            # Message signatures
│   │   └── cavv.c                  # CAVV generation
│   └── web/
│       ├── http_server.c           # Basic HTTP server
│       └── json.c                  # JSON parsing
├── static/
│   ├── checkout.html               # Checkout page
│   ├── challenge.html              # Challenge iframe
│   └── style.css
├── tests/
│   ├── test_areq.c
│   ├── test_risk_engine.c
│   └── test_challenge.c
├── Makefile
└── README.md

Core API Design

// threeds_server.h
typedef struct {
    char trans_id[37];                // UUID
    char merchant_id[32];
    char merchant_name[64];
    int purchase_amount;              // In minor units (cents)
    char purchase_currency[4];        // ISO currency code
} TransactionInfo;

typedef struct {
    char acct_number[20];
    char card_expiry[5];              // YYMM
    char cardholder_name[64];
} CardInfo;

typedef struct {
    char user_agent[256];
    char accept_header[128];
    char ip_address[46];
    char language[8];
    int screen_width;
    int screen_height;
    int color_depth;
    int timezone_offset;
    bool java_enabled;
    bool javascript_enabled;
} BrowserInfo;

// Build and send AReq
typedef struct {
    char trans_status;                // Y, N, C, U, A, R
    char eci[3];                      // 05, 06, 07
    char cavv[64];                    // Base64 encoded
    char acs_url[256];                // For challenge
    char acs_trans_id[37];
    bool challenge_required;
} AResResult;

AResResult initiate_authentication(
    const TransactionInfo* trans,
    const CardInfo* card,
    const BrowserInfo* browser
);

// acs.h
typedef struct {
    int risk_score;                   // 0-100
    char decision;                    // Y (frictionless), C (challenge), N (deny)
    char reason[64];
} RiskDecision;

RiskDecision assess_risk(
    const char* pan,
    int amount,
    const BrowserInfo* browser,
    const char* merchant_id
);

typedef struct {
    char otp[7];                      // 6 digits
    time_t expires_at;
    char trans_id[37];
} Challenge;

Challenge generate_challenge(const char* trans_id, const char* phone_last4);
bool verify_challenge(const char* trans_id, const char* otp_entered);

Solution Architecture

System Design

┌─────────────────────────────────────────────────────────────────────────┐
│                    3DS SIMULATOR ARCHITECTURE                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  BROWSER                                                                 │
│  ═══════                                                                 │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    checkout.html                                 │    │
│  │                                                                  │    │
│  │   • Card form                                                    │    │
│  │   • Browser data collection (JS)                                 │    │
│  │   • 3DS Method iframe (device fingerprinting)                   │    │
│  │   • Challenge iframe container                                   │    │
│  │                                                                  │    │
│  └──────────────────────────┬──────────────────────────────────────┘    │
│                             │                                            │
│                             │ POST /initiate-3ds                        │
│                             │ {card, browser_data, transaction}          │
│                             ▼                                            │
│  MERCHANT SERVER (3DS Server)                                            │
│  ════════════════════════════                                            │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    threeds_server.c                              │    │
│  │                                                                  │    │
│  │   ┌────────────────────┐   ┌────────────────────┐              │    │
│  │   │  Build AReq        │   │  Parse ARes        │              │    │
│  │   │  (protocol/areq.c) │   │  (protocol/ares.c) │              │    │
│  │   └─────────┬──────────┘   └──────────┬─────────┘              │    │
│  │             │                         │                         │    │
│  │             │ AReq JSON               │ ARes JSON               │    │
│  │             │                         │                         │    │
│  └─────────────┼─────────────────────────┼─────────────────────────┘    │
│                │                         │                              │
│                ▼                         │                              │
│  DIRECTORY SERVER                       │                              │
│  ════════════════                       │                              │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    ds.c                                          │    │
│  │                                                                  │    │
│  │   ┌────────────────────┐   ┌────────────────────┐              │    │
│  │   │  Validate Message  │   │  Route by BIN      │              │    │
│  │   │                    │   │  (BIN → ACS URL)   │              │    │
│  │   └─────────┬──────────┘   └──────────┬─────────┘              │    │
│  │             │                         │                         │    │
│  │             │ AReq                    │ ARes                    │    │
│  │             ▼                         │                         │    │
│  └─────────────┼─────────────────────────┼─────────────────────────┘    │
│                │                         │                              │
│                ▼                         │                              │
│  ACCESS CONTROL SERVER (ACS)            │                              │
│  ═══════════════════════════            │                              │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    acs.c                                         │    │
│  │                                                                  │    │
│  │   ┌────────────────────┐   ┌────────────────────┐              │    │
│  │   │  Risk Engine       │   │  Challenge Logic   │              │    │
│  │   │  (risk_engine.c)   │   │  (challenge.c)     │              │    │
│  │   │                    │   │                    │              │    │
│  │   │  • Device history  │   │  • OTP generation  │              │    │
│  │   │  • Amount analysis │   │  • OTP validation  │              │    │
│  │   │  • Behavioral      │   │  • Timeout         │              │    │
│  │   └─────────┬──────────┘   └──────────┬─────────┘              │    │
│  │             │                         │                         │    │
│  │             ▼                         │                         │    │
│  │   ┌────────────────────────────────────────────────────────┐   │    │
│  │   │  Decision:                                              │   │    │
│  │   │  • Frictionless (transStatus=Y) → Return ARes          │   │    │
│  │   │  • Challenge (transStatus=C) → Serve challenge UI      │   │    │
│  │   │  • Deny (transStatus=N) → Return ARes with reason      │   │    │
│  │   └────────────────────────────────────────────────────────┘   │    │
│  │                                                                  │    │
│  │   ┌────────────────────────────────────────────────────────┐   │    │
│  │   │  CAVV Generation (crypto/cavv.c)                        │   │    │
│  │   │  • Sign authentication result                          │   │    │
│  │   │  • Include transaction details                          │   │    │
│  │   └────────────────────────────────────────────────────────┘   │    │
│  │                                                                  │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Risk Engine Design

// risk_engine.c

typedef struct {
    // Device fingerprint
    char device_id[64];           // Hash of browser characteristics

    // History
    int previous_purchases;       // From this device
    int failed_attempts;          // Recent failures
    time_t last_purchase;

    // Current transaction
    int amount;
    bool shipping_matches_billing;
    char merchant_category[8];    // MCC code
} RiskFactors;

#define RISK_WEIGHT_DEVICE_NEW      25
#define RISK_WEIGHT_IP_NEW          15
#define RISK_WEIGHT_HIGH_AMOUNT     20
#define RISK_WEIGHT_DIFFERENT_SHIP  10
#define RISK_WEIGHT_ODD_TIME        5
#define RISK_WEIGHT_FAILED_RECENT   15
#define RISK_WEIGHT_SUSPICIOUS_MCC  10

int calculate_risk_score(const RiskFactors* factors) {
    int score = 0;

    // New device
    if (factors->previous_purchases == 0) {
        score += RISK_WEIGHT_DEVICE_NEW;
    }

    // High amount (threshold varies by merchant)
    if (factors->amount > 10000) {  // $100 in cents
        score += RISK_WEIGHT_HIGH_AMOUNT;
    }

    // Different shipping
    if (!factors->shipping_matches_billing) {
        score += RISK_WEIGHT_DIFFERENT_SHIP;
    }

    // Recent failures
    if (factors->failed_attempts > 0) {
        score += RISK_WEIGHT_FAILED_RECENT * factors->failed_attempts;
    }

    return score > 100 ? 100 : score;
}

RiskDecision assess_risk(/*...*/) {
    RiskFactors factors = gather_factors(/*...*/);
    int score = calculate_risk_score(&factors);

    RiskDecision decision;
    decision.risk_score = score;

    if (score < 30) {
        decision.decision = 'Y';  // Frictionless
        strcpy(decision.reason, "Low risk transaction");
    } else if (score < 70) {
        decision.decision = 'C';  // Challenge
        strcpy(decision.reason, "Moderate risk - verification needed");
    } else {
        decision.decision = 'N';  // Deny
        strcpy(decision.reason, "High risk - declined");
    }

    return decision;
}

Implementation Guide

Phase 1: Protocol Messages

Goal: Implement AReq/ARes message structures.

// areq.c
#include <json.h>

typedef struct {
    char message_type[8];           // "AReq"
    char message_version[8];        // "2.2.0"
    char three_ds_server_trans_id[37];
    char acct_number[20];
    char card_expiry_date[5];
    char purchase_amount[16];
    char purchase_currency[4];
    char merchant_name[64];
    char device_channel[3];
    // Browser info
    char browser_accept_header[256];
    char browser_ip[46];
    char browser_language[8];
    char browser_user_agent[512];
    // ... many more fields
} AReq;

char* areq_to_json(const AReq* areq) {
    json_t* root = json_object();

    json_object_set_new(root, "messageType",
                        json_string(areq->message_type));
    json_object_set_new(root, "messageVersion",
                        json_string(areq->message_version));
    // ... all fields

    char* json_str = json_dumps(root, JSON_COMPACT);
    json_decref(root);
    return json_str;
}

Phase 2: Basic Server

Goal: HTTP server to handle checkout flow.

// Using mongoose or libmicrohttpd

void handle_initiate_3ds(Request* req, Response* res) {
    // Parse card, browser data, transaction from request
    CardInfo card;
    BrowserInfo browser;
    TransactionInfo trans;
    parse_checkout_request(req->body, &card, &browser, &trans);

    // Build AReq
    AReq areq = build_areq(&card, &browser, &trans);

    // Send to DS (in production, over TLS mutual auth)
    AResResult ares = send_areq_to_ds(&areq);

    if (ares.challenge_required) {
        // Return challenge URL to browser
        json_response(res, 200, "{\"challenge\": true, \"acsUrl\": \"%s\"}",
                     ares.acs_url);
    } else if (ares.trans_status == 'Y') {
        // Proceed with authorization
        AuthResult auth = authorize_transaction(&trans, ares.cavv, ares.eci);
        json_response(res, 200, "{\"success\": true, \"authCode\": \"%s\"}",
                     auth.auth_code);
    } else {
        json_response(res, 200, "{\"success\": false, \"reason\": \"%s\"}",
                     ares.reason);
    }
}

Phase 3: Directory Server Routing

Goal: Route AReq to correct ACS by BIN.

// routing.c

typedef struct {
    char bin_start[9];
    char bin_end[9];
    char acs_url[256];
    char acs_id[32];
} BinRoute;

static BinRoute routes[] = {
    {"40000000", "49999999", "http://localhost:8082/acs", "VISA_ACS_001"},
    {"51000000", "55999999", "http://localhost:8083/acs", "MC_ACS_001"},
    {"34000000", "34999999", "http://localhost:8084/acs", "AMEX_ACS_001"},
    // ...
};

const char* route_to_acs(const char* pan) {
    char bin[9];
    strncpy(bin, pan, 8);
    bin[8] = '\0';

    for (int i = 0; i < sizeof(routes)/sizeof(routes[0]); i++) {
        if (strcmp(bin, routes[i].bin_start) >= 0 &&
            strcmp(bin, routes[i].bin_end) <= 0) {
            return routes[i].acs_url;
        }
    }
    return NULL;  // Card not enrolled
}

Phase 4: ACS Risk Engine

Goal: Make frictionless vs challenge decisions.

See Risk Engine Design section above.

Phase 5: Challenge Flow

Goal: Implement OTP challenge.

// challenge.c

// In-memory challenge store (use Redis in production)
static Challenge active_challenges[1000];
static int challenge_count = 0;

Challenge generate_challenge(const char* trans_id, const char* phone_last4) {
    Challenge c;
    strncpy(c.trans_id, trans_id, 36);
    c.trans_id[36] = '\0';

    // Generate 6-digit OTP
    unsigned int seed;
    RAND_bytes((unsigned char*)&seed, sizeof(seed));
    snprintf(c.otp, 7, "%06d", seed % 1000000);

    c.expires_at = time(NULL) + 300;  // 5 minutes

    // Store
    active_challenges[challenge_count++] = c;

    // In production: actually send SMS via Twilio, etc.
    printf("[ACS] Sending OTP %s to phone ending in %s\n", c.otp, phone_last4);

    return c;
}

bool verify_challenge(const char* trans_id, const char* otp_entered) {
    for (int i = 0; i < challenge_count; i++) {
        if (strcmp(active_challenges[i].trans_id, trans_id) == 0) {
            if (time(NULL) > active_challenges[i].expires_at) {
                return false;  // Expired
            }
            return strcmp(active_challenges[i].otp, otp_entered) == 0;
        }
    }
    return false;  // Not found
}

Phase 6: CAVV Generation

Goal: Generate cryptographic authentication value.

// cavv.c

// CAVV structure (simplified - real CAVV is more complex)
typedef struct {
    char algorithm;          // 0 = HMAC, 1 = CVN etc.
    char version;            // Protocol version
    char key_indicator[2];   // Which key was used
    char auth_result;        // Y/A/N etc.
    char trans_id[4];        // Abbreviated trans ID
    char mac[20];            // HMAC of above
} CAVV;

char* generate_cavv(const char* trans_id, char auth_result,
                    const unsigned char* key) {
    CAVV cavv;
    cavv.algorithm = 0;
    cavv.version = 2;
    cavv.auth_result = auth_result;

    // Copy first 4 bytes of trans ID
    memcpy(cavv.trans_id, trans_id, 4);

    // Generate HMAC
    unsigned char to_mac[8];
    to_mac[0] = cavv.algorithm;
    to_mac[1] = cavv.version;
    to_mac[2] = cavv.auth_result;
    memcpy(to_mac + 3, cavv.trans_id, 4);

    HMAC(EVP_sha1(), key, 16, to_mac, 7, cavv.mac, NULL);

    // Base64 encode entire structure
    char* b64 = base64_encode((unsigned char*)&cavv, sizeof(cavv));
    return b64;
}

Testing Strategy

Protocol Compliance Tests

void test_areq_required_fields() {
    AReq areq = {0};
    // Missing required field
    char* json = areq_to_json(&areq);

    // Should fail validation
    assert(validate_areq(json) == false);

    // Add required fields
    strcpy(areq.message_type, "AReq");
    strcpy(areq.message_version, "2.2.0");
    // ... add all required

    json = areq_to_json(&areq);
    assert(validate_areq(json) == true);
}

Risk Engine Tests

void test_low_risk_frictionless() {
    RiskFactors factors = {
        .previous_purchases = 10,
        .failed_attempts = 0,
        .amount = 1000,  // $10
        .shipping_matches_billing = true
    };

    int score = calculate_risk_score(&factors);
    assert(score < 30);  // Should be frictionless
}

void test_high_risk_challenge() {
    RiskFactors factors = {
        .previous_purchases = 0,  // New device
        .failed_attempts = 2,
        .amount = 50000,  // $500
        .shipping_matches_billing = false
    };

    int score = calculate_risk_score(&factors);
    assert(score >= 30);  // Should require challenge
}

End-to-End Flow Tests

#!/bin/bash
# test_3ds_flow.sh

# Start all servers
./ds_server &
./acs_server &
./merchant_server &
sleep 2

# Test frictionless flow (low amount, known device)
RESPONSE=$(curl -s -X POST http://localhost:8080/initiate-3ds \
  -H "Content-Type: application/json" \
  -d '{
    "pan": "4111111111111111",
    "amount": 1000,
    "browserInfo": {...}
  }')

assert_contains "$RESPONSE" '"transStatus":"Y"'

# Test challenge flow (high amount)
RESPONSE=$(curl -s -X POST http://localhost:8080/initiate-3ds \
  -H "Content-Type: application/json" \
  -d '{
    "pan": "4111111111111111",
    "amount": 100000,
    "browserInfo": {...}
  }')

assert_contains "$RESPONSE" '"challenge":true'

Common Pitfalls & Debugging

Pitfall 1: Incorrect Version Handling

Symptom: DS rejects messages.

Cause: Protocol version mismatch between components.

Fix: Ensure all components use same messageVersion.

Pitfall 2: CAVV Validation Failure

Symptom: Authorization fails despite successful authentication.

Cause: CAVV format doesn’t match network expectations.

Fix: Follow EMVCo specification exactly for CAVV structure.

Pitfall 3: Challenge Iframe Issues

Symptom: Challenge doesn’t display.

Cause: CSP blocking iframe, or cross-origin issues.

Fix: Set proper headers: X-Frame-Options: ALLOW-FROM merchant.com.


Extensions & Challenges

Extension 1: Device Fingerprinting

Implement 3DS Method for device fingerprinting before authentication.

Extension 2: SCA Exemptions

Implement Strong Customer Authentication exemptions (low value, recurring, etc.)

Extension 3: Decoupled Authentication

Implement app-based push notification authentication.

Extension 4: Real Card Network Integration

Integrate with Visa/Mastercard test environments.


Resources

Specifications

  • EMVCo 3D Secure 2.x Specification (free from emvco.com)
  • EMVCo 3D Secure SDK Specification
  • PCI 3DS Core Security Standard

Books

Topic Book
Digital Signatures Serious Cryptography Ch. 13
Web Security Bug Bounty Bootcamp by Vickie Li
Risk-Based Auth Security in Computing by Pfleeger

Self-Assessment Checklist

  • AReq/ARes messages comply with EMVCo spec
  • Risk engine makes reasonable decisions
  • Challenge flow works end-to-end
  • CAVV is generated correctly
  • Frictionless flow works for low-risk transactions
  • Can explain liability shift
  • Understand the three-domain model
  • Iframe security is properly handled

What’s Next?

You now understand e-commerce authentication. Move to Project 5: Mini Payment Gateway to build a system that ties together tokenization, P2PE, and 3DS with PCI-compliant architecture.