# Feature: Key Exchange Transaction

**Transaction Types:** TMK Key Exchange, PIN IPEK Exchange
**Processor Class:** `ManagementTransactionProcessor`
**Transaction Type Enum:** `TxnType.LOGON` (management transactions share this type)

---

## 1. Overview

Key Exchange establishes cryptographic keys between the POS terminal and the bank acquirer for securing PIN blocks. Two sub-types are supported:

1. **TMK (Terminal Master Key) Exchange** — Processing code `810000` (POS) / `991380` (YSP). Downloads the encrypted TMK from the host to the terminal. DE-125 carries the key block.

2. **PIN IPEK (Initial PIN Encryption Key) Exchange** — Processing code `811000` (POS) / `990280` (YSP). Downloads the IPEK for DUKPT PIN encryption. Uses DE53 (KSN) to identify the terminal's key injection device.

Both sub-types use MTI 0800. No financial data (PAN, amount, or currency) is involved. No temp transaction is created. No receipt is generated.

---

## 2. Flow Diagrams

### 2a. TMK Key Exchange

```
POS Terminal                  jPOS Middleware                  Bank Acquirer (YSP)
     |                               |                                    |
     |--- MTI 0800 (DE3=810000) ---->|                                    |
     |    DE41=41448413              |                                    |
     |    DE62=98250623730001        |                                    |
     |                               |-- validateAndStoreRequest()        |
     |                               |-- preprocess() [ManagementTxnProc] |
     |                               |   clearReversal() + clearTemp      |
     |                               |-- onboardRequest() [no-op]         |
     |                               |-- translator.toMessage()           |
     |                               |   getNetworkMsgTmK()               |
     |                               |   DE3=991380, DE125=<key block>    |
     |                               |--- MTI 0800 (DE3=991380) -------->|
     |                               |    DE125=0123456789ABCDEF...       |
     |                               |<-- MTI 0810 (DE39=00, DE62=enc key)|
     |                               |-- postProcess()                    |
     |                               |   jposResponse.set(63, isoMsg.get(62))
     |<-- MTI 0810 (DE3=810000,      |                                    |
     |    DE39=00, DE63=enc key)-----|                                    |
```

### 2b. PIN IPEK Exchange

```
POS Terminal                  jPOS Middleware                  Bank Acquirer (YSP)
     |                               |                                    |
     |--- MTI 0800 (DE3=811000) ---->|                                    |
     |    DE41=41448413              |                                    |
     |    DE63=<KSN>                 |                                    |
     |                               |-- translator.toMessage()           |
     |                               |   getNetworkMsgPinIpek()           |
     |                               |   DE3=990280, DE53=KSN, DE70=161  |
     |                               |--- MTI 0800 (DE3=990280) -------->|
     |                               |<-- MTI 0810 (DE39=00, DE62=IPEK)--|
     |<-- MTI 0810 (DE39=00) --------|                                    |
```

---

## 3. ISO-8583 Message Specification

### 3.1 TMK Key Exchange — POS Terminal Request

| DE # | Field Name                          | Format        | M/C | Description / Example                   |
|------|-------------------------------------|---------------|-----|-----------------------------------------|
| MTI  | Message Type Indicator              | BCD F4        | M   | `0800`                                  |
| 3    | Processing Code                     | BCD F6        | M   | `810000` (POS TMK request indicator)    |
| 11   | STAN                                | BCD F6        | M   | `000212`                                |
| 41   | Card Acceptor Terminal ID           | ASCII F8      | M   | `41448413`                              |
| 62   | Terminal Serial Number              | ASCII LLLVAR  | M   | `98250623730001` (device serial number) |

### 3.2 TMK Key Exchange — Acquirer Request (Middleware -> YSP)

`getNetworkMsgTmK()` constructs:

| DE # | Field Name               | Format        | Source / Value                                                    |
|------|--------------------------|---------------|-------------------------------------------------------------------|
| MTI  |                          | BCD F4        | `0800`                                                            |
| 3    | Processing Code          | BCD F6        | `991380` (YSP TMK request code)                                   |
| 11   | STAN                     | BCD F6        | Bank-assigned STAN (from `StanBatchNumberService`)                |
| 24   | NII                      | BCD F3        | From acquirer config                                              |
| 41   | Card Acceptor Terminal ID| ASCII F8      | Bank TID                                                          |
| 42   | Card Acceptor Merchant ID| ASCII F15     | Bank MID                                                          |
| 43   | Card Acceptor Name       | ASCII F40     | `"Mercury PAY"` (hardcoded)                                       |
| 63   | Terminal Serial Number   | ASCII LLLVAR  | From POS request DE62 (`isoMsg.getString(62)`)                    |
| 125  | Key Block                | Binary LLLVAR | Encrypted Terminal Master Key (32-char hex, e.g. `0123456789ABCDEF0123456789ABCDEF`) |

### 3.3 TMK Key Exchange — Response (YSP -> Middleware -> POS Terminal)

| DE # | Field Name               | Format        | M/C | Description / Example                                       |
|------|--------------------------|---------------|-----|-------------------------------------------------------------|
| MTI  |                          | BCD F4        | M   | `0810`                                                      |
| 3    | Processing Code          | BCD F6        | M   | `991380` -> translated back to `810000` for POS             |
| 11   | STAN                     | BCD F6        | M   | Echoed                                                      |
| 12   | Local Time               | BCD F6        | C   | Response time                                               |
| 13   | Local Date               | BCD F4        | C   | Response date                                               |
| 24   | NII                      | BCD F3        | C   | From acquirer                                               |
| 39   | Response Code            | ASCII F2      | M   | `00` = Key loaded successfully                              |
| 41   | Terminal ID              | ASCII F8      | M   | Restored to POS TID (`41448413`)                            |
| 42   | Merchant ID              | ASCII F15     | M   | Restored to POS MID                                         |
| 62   | Encrypted Key + KCV      | ASCII LLLVAR  | M   | `325838F288258A30B6418117EF9BFD7767E852` (38 chars from bank)|
| 63   | Terminal Serial Number   | ASCII LLLVAR  | M   | Translator sets: `jposResponse.set(63, isoMsg.getString(62))` — DE62 (encrypted key) is moved to DE63 in the POS response |

> **DE62/DE63 swap:** `JposYspTranslator.fromMessage()` for `0800` sets `jposResponse.set(63, isoMsg.getString(62))`. The bank returns the encrypted key in DE62; the POS expects it in DE63. DE53 and DE70 are unset in the POS response.

### 3.4 PIN IPEK Exchange — POS Terminal Request

| DE # | Field Name               | Format        | M/C | Description                             |
|------|--------------------------|---------------|-----|-----------------------------------------|
| MTI  |                          | BCD F4        | M   | `0800`                                  |
| 3    | Processing Code          | BCD F6        | M   | `811000` (POS PIN IPEK request code)    |
| 11   | STAN                     | BCD F6        | M   | Terminal STAN                           |
| 41   | Terminal ID              | ASCII F8      | M   | `41448413`                              |
| 63   | KSN (Key Serial Number)  | ASCII LLLVAR  | M   | `98250623730001` (15-digit KSN)         |

### 3.5 PIN IPEK Exchange — Acquirer Request (Middleware -> YSP)

`getNetworkMsgPinIpek()` constructs:

| DE # | Field Name               | Format        | Source / Value                                  |
|------|--------------------------|---------------|-------------------------------------------------|
| MTI  |                          | BCD F4        | `0800`                                          |
| 3    | Processing Code          | BCD F6        | `990280` (YSP PIN IPEK code)                    |
| 7    | Transmission Date/Time   | BCD F10       | `getDateTime()` — current UTC datetime          |
| 11   | STAN                     | BCD F6        | From POS request DE11                           |
| 12   | Local Time               | BCD F6        | `getTime()` — current time                      |
| 41   | Terminal ID              | ASCII F8      | Bank TID                                        |
| 42   | Merchant ID              | ASCII F15     | Bank MID                                        |
| 53   | KSN                      | ASCII LLVAR   | From POS request DE63 (`isoMsg.getString(63)`)  |
| 70   | Network Mgmt Info Code   | BCD F3        | `161` = Key Exchange                            |

---

## 4. Processing Codes

| POS Code | YSP Code | Meaning                                         |
|----------|----------|-------------------------------------------------|
| `810000` | `991380` | TMK (Terminal Master Key) download              |
| `811000` | `990280` | PIN IPEK (Initial PIN Encryption Key) download  |

---

## 5. Response Codes

| DE39 | Meaning               | Middleware Handling                             |
|------|-----------------------|-------------------------------------------------|
| `00` | Key exchange approved | Response forwarded with encrypted key in DE63   |
| `83` | Acquirer Timeout      | `SocketTimeoutException`; no reversal created   |
| `96` | System Malfunction    | Key exchange failed; terminal must retry        |

---

## 6. Rules Engine

**Not evaluated** for Key Exchange transactions. `ReceiptGenerator.generateReceipt()` explicitly skips MTI `0800`. There is no financial context (no PAN, amount, or currency) to evaluate.

---

## 7. Receipt Generation

**Not applicable.** `ReceiptGenerator.generateReceipt()` returns `null` at the start when `"0800".equals(mti)`. No DE-63 receipt is generated for any key exchange message.

---

## 8. Error Handling

| Scenario                   | Behaviour                                                     |
|----------------------------|---------------------------------------------------------------|
| DE41 not in DB             | `errorCode = INVALID_POS_TERMINAL`, DE39=`76`                 |
| Terminal busy              | `errorCode = TERMINAL_BUSY`, DE39=`81`                        |
| `SocketTimeoutException`   | `errorCode = ACQUIRER_TIMED_OUT`, DE39=`83`; **no reversal**  |
| Null response              | Same as above; management transactions do not reverse         |
| Invalid DE3 for 0800       | `toMessage()` returns null -> `INVALID_POS_ACQUIRER`, DE39=`77`|

---

## 9. BDD Scenarios

### Scenario 1: Successful TMK Key Exchange

```
Given a POS terminal with TID=41448413 is registered
And the acquirer connection to YSP is active
When the terminal sends MTI 0800 with DE3=810000, DE11=000212, DE41=41448413, DE62=98250623730001
Then getNetworkMsgTmK() builds MTI 0800 with DE3=991380, DE125=0123456789ABCDEF0123456789ABCDEF
And the acquirer responds MTI 0810 with DE39=00, DE62=325838F288258A30B6418117EF9BFD7767E852
And the translator moves DE62 to DE63 in the POS response
And the POS receives MTI 0810 with DE39=00, DE3=810000, DE63=<encrypted_key>
```

### Scenario 2: Successful PIN IPEK Exchange

```
Given a POS terminal with TID=41448413 is registered
When the terminal sends MTI 0800 with DE3=811000, DE11=000213, DE63=98250623730001
Then getNetworkMsgPinIpek() builds MTI 0800 with DE3=990280, DE53=98250623730001, DE70=161
And the acquirer responds MTI 0810 with DE39=00 and DE62 containing the IPEK
And the POS receives MTI 0810 with DE39=00
```

### Scenario 3: Key Exchange — Acquirer Timeout

```
Given the acquirer is slow to respond
When the terminal sends MTI 0800 with DE3=810000
And acquirerChannel.transceive() throws SocketTimeoutException
Then errorCode = ACQUIRER_TIMED_OUT
And no reversal is created (no financial transaction at risk)
And the POS receives MTI 0810 with DE39=83
And the terminal must retry the key exchange
```

### Scenario 4: Key Exchange — Clears Stale Pending Reversal First

```
Given a pending PosTransactionReversal exists for terminal TID=41448413
When the terminal sends a key exchange (MTI 0800 with DE3=810000)
Then preprocess() calls clearReversal() which sends the pending MTI 0400 to the bank
And the reversal completes
And the key exchange then proceeds normally
```

### Scenario 5: Invalid Processing Code in 0800

```
Given the terminal sends MTI 0800 with an unrecognised DE3 value (e.g., "999999")
Then JposYspTranslator.toMessage() returns null for the unknown processing code
And errorCode = INVALID_POS_ACQUIRER
And the POS receives MTI 0810 with DE39=77
```

---

## 10. Business Requirements

### BR-KE-01 — Purpose
The system shall support cryptographic key exchange between POS terminals and the bank acquirer to establish secure PIN encryption before any financial transaction can be processed.

### BR-KE-02 — Supported Key Types
The system shall support two key exchange sub-types:
- **TMK (Terminal Master Key)** — downloads the master key used to derive working keys
- **PIN IPEK (Initial PIN Encryption Key)** — downloads the base key for DUKPT PIN encryption

### BR-KE-03 — Trigger
A POS terminal shall initiate Key Exchange by sending MTI `0800` with:
- DE3 = `810000` for TMK
- DE3 = `811000` for PIN IPEK

### BR-KE-04 — Terminal Registration
The system shall reject any Key Exchange request from a terminal not registered in the terminal database (DE41 not found), returning DE39 = `76`.

### BR-KE-05 — No Financial Data
Key Exchange messages shall carry no card data (PAN, Track 2, PIN) and no transaction amount. The system shall not create any transaction record in the database for this message type.

### BR-KE-06 — No Receipt
The system shall not generate a receipt (DE-63) for any Key Exchange response.

### BR-KE-07 — No Reversal
The system shall not initiate a reversal on Key Exchange timeout or failure. There are no funds at risk in this flow.

### BR-KE-08 — Housekeeping Before Key Exchange
Before processing a Key Exchange, the system shall:
- Dispatch any pending reversals for the requesting terminal
- Initiate reversals for any stale orphaned transactions associated with that terminal

### BR-KE-09 — Acquirer Code Mapping
The system shall translate POS processing codes to the YSP acquirer codes before forwarding:

| POS Code | YSP Code | Meaning  |
|----------|----------|----------|
| `810000` | `991380` | TMK      |
| `811000` | `990280` | PIN IPEK |

### BR-KE-10 — TMK Key Delivery
For a TMK exchange, the system shall:
- Include the terminal serial number (from POS DE62) in the acquirer request (as DE63)
- Include the encrypted key block in DE125 of the acquirer request
- Return the bank's encrypted key (received in acquirer DE62) to the POS terminal in DE63

### BR-KE-11 — PIN IPEK Key Delivery
For a PIN IPEK exchange, the system shall:
- Include the KSN (from POS DE63) in the acquirer request as DE53
- Set DE70 = `161` (Key Exchange) in the acquirer request

### BR-KE-12 — Terminal ID Restoration
The system shall replace the bank TID/MID in the acquirer response with the original POS TID/MID before returning the response to the terminal.

### BR-KE-13 — Timeout Behaviour
If the acquirer does not respond within the configured timeout, the system shall return DE39 = `83` to the POS terminal. The terminal must retry the key exchange independently.

### BR-KE-14 — Success Criteria
A Key Exchange is considered successful when the acquirer responds with DE39 = `00`. Any other response code is treated as failure.

### BR-KE-15 — Unknown Processing Code
If the terminal sends MTI `0800` with an unrecognised DE3 value, the system shall return DE39 = `77` (Invalid Acquirer) without contacting the bank.
