Skip to content

Commit

Permalink
Upgrade to jPOS 2.1.8, use new CryptogramSpec, and remove obsolete AR…
Browse files Browse the repository at this point in the history
…QC settings
  • Loading branch information
tilln committed Feb 25, 2023
1 parent 722ffba commit 891826b
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 163 deletions.
66 changes: 35 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ based on the excellent [jPOS framework](http://jpos.org/). Includes the followin

#### Prerequisites
A so-called Packager is required to transform ("pack") the message into its binary representation for sending it over the wire.
This plugin uses a jPOS [Generic Packager](http://jpos.org/doc/proguide.pdf#%5B%7B%22num%22%3A1736%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C54%2C133.877%2Cnull%5D)
This plugin uses a jPOS [Generic Packager](https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch04/genericpackager.adoc)
that needs to be configured with an XML file.

Often one of the jPOS [packager configuration files](https://github.com/jpos/jPOS/tree/v2_1_6/jpos/src/dist/cfg/packager)
Often one of the jPOS [packager configuration files](https://github.com/jpos/jPOS/tree/v2_1_8/jpos/src/dist/cfg/packager)
may be used as-is or with few customisations.

#### Sample Message
Expand Down Expand Up @@ -69,8 +69,8 @@ A static header string for all messages (sent and received).
Note that some Channels use dynamic headers instead (e.g. VAPChannel).
- *Advanced Configuration*:
Channel-dependent properties can be specified via *Name*/*Value* pairs.
For example, [`srcid` and `dstid`](https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/iso/channel/VAPChannel.java#L236-L237)
for VAPChannel's [Base1Header](https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/iso/header/BASE1Header.java).
For example, [`srcid` and `dstid`](https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/iso/channel/VAPChannel.java#L236-L237)
for VAPChannel's [Base1Header](https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/iso/header/BASE1Header.java).
- *SSL Settings*:
For SSL/TLS connections, the *Keystore File*
(protected with *Keystore Password* for the file and *Key Password* for a private key) should contain:
Expand All @@ -79,7 +79,7 @@ For SSL/TLS connections, the *Keystore File*
* Server mode: the server certificate (with public and private key).
- *Mux Settings* (since v1.1):
Control how the Mux finds matches between outgoing requests and incoming response messages.
See [QMUX documentation](https://github.com/jpos/jPOS/blob/v2_1_6/doc/src/asciidoc/ch08/qmux.adoc#mti-mapping-and-default-key)
See [QMUX documentation](https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch08/qmux.adoc#mti-mapping-and-default-key)
for further details.
* *MTI Mapping*: 3 ten-digit numbers representing how the first 3 MTI digits are mapped between request and response.
Example (default): "0123456789 0123456789 0022446789" maps response MTI `0110` to request MTI `0100`.
Expand Down Expand Up @@ -133,8 +133,8 @@ For SSL/TLS connections, the *Keystore File*
##### Implementation Details
This component encapsulates a jPOS [Q2 container](http://jpos.org/doc/proguide.pdf#%5B%7B%22num%22%3A2464%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C54%2C769.889%2Cnull%5D)
and [QBeans services](http://jpos.org/doc/proguide.pdf#%5B%7B%22num%22%3A3393%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C54%2C769.889%2Cnull%5D).
This component encapsulates a jPOS [Q2 container](https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/master.adoc#q2)
and [QBeans services](https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/master.adoc#8-q2-jpos-services).
It manages either set of 3 components (depending on client or server mode):
- ChannelAdaptor, Channel and QMUX
- QServer, Channel and QMUX
Expand Down Expand Up @@ -333,26 +333,28 @@ the MAC field will be the next multiple of 64 from the last field in the message
- *EMV/ICC Data Field Number* (usually 55): The ARQC input fields will be taken from **subfields** of this field
(unless *Transaction Data* is specified below),
and the calculated ARQC value will be added as an additional subfield (tag `9F26`).
- *IMKAC (hex)*: Clear ICC Master Key for Application Cryptogram calculation.
- *Session Key Derivation Method*: How to derive the UDK from the Master Key.
- *Primary Account Number (PAN)*: Input parameter for session key derivation.
- *Account Sequence Number*: Input parameter for session key derivation (2 digits).
- *IMKAC (hex)*: Clear ICC Master Key for Application Cryptogram calculation (Triple-DES key, 32 hex digits).
- *Primary Account Number (PAN)*: Input parameter for session key derivation.
Must be provided unless the ICC data contains this in tag `5A`.
- *Account Sequence Number (hex)*: Input parameter for session key derivation (2 hex digits).
Must be provided unless the ICC data contains this in tag `5F34`.
- *Transaction Data (hex)*: Input data for ARQC calculation (as byte sequence).
If left blank, relevant fields will be automatically extracted from the ICC Data field.

Which ICC subfields are to be included in the ARQC calculation can be configured (globally) by specifying the tags
in the JMeter property `jmeter.iso8583.arqcInputTags` (default: `9F02,9F03,9F1A,95,5F2A,9A,9C,9F37,82,9F36,9F10`).
Missing ARQC input tags will be ignored, i.e. no validation is performed that all mandatory tags are present.

The JMeter property `jmeter.iso8583.arqcFromFullIADForCVNs` (default: `12,16`; since v1.2)
determines for which CVNs the entire Issuer Application Data (tag `9F10`)
is to be included in the ARQC calculation instead of the CVR portion only.
If left blank, relevant fields will be automatically extracted from the ICC Data field.
Otherwise, for example, if non-standard tags are to be included in the cryptogram calculation, the raw input bytes
can be supplied in this field.

**Note:** Changed behaviour! For v1.0 the data in this field is *appended* to the automatically extracted fields,
whereas as of v1.1 data in this field overrides the extraction.
- *Padding (hex)* (since v1.1): Padding bytes to append to transaction data before ARQC calculation
- *Padding (hex)* (since v1.1): Optional, additional padding bytes to append to transaction data before ARQC calculation
(leave blank for zero-padding, 80 for ISO9797-1 Method 2).

**Note:** Changed behaviour! Until v1.2 the input field
*Session Key Derivation Method* (how to derive the UDK from the Master Key) had to be set explicitly.
As of v1.3 this is obsolete as it will be determined automatically by evaluating the Issuer Application Data field (tag `9F10`).

Likewise, as of v1.3, the JMeter properties `jmeter.iso8583.arqcInputTags` and `jmeter.iso8583.arqcFromFullIADForCVNs` have been
removed as jPOS [handles](https://github.com/jpos/jPOS/pull/499) this cryptogram logic internally.

<h3 id="functions">Crypto Functions (since v1.1)</h3>

#### __calculateCVV
Expand Down Expand Up @@ -429,13 +431,13 @@ Extract the [zip package](https://jmeter-plugins.org/files/packages/tilln-iso858

1. Copy the [jmeter-iso8583 jar file](https://github.com/tilln/jmeter-iso8583/releases/download/1.2/jmeter-iso8583-1.2.jar) into JMeter's `lib/ext` directory.
2. Copy the following dependencies into JMeter's `lib` directory (and optionally remove older versions of any of those jar files):
* [org.jpos / jpos](https://search.maven.org/remotecontent?filepath=org/jpos/jpos/2.1.6/jpos-2.1.6.jar)
* [org.bouncycastle / bcprov-jdk15on](https://search.maven.org/remotecontent?filepath=org/bouncycastle/bcprov-jdk15on/1.67/bcprov-jdk15on-1.67.jar)
* [org.bouncycastle / bcpg-jdk15on](https://search.maven.org/remotecontent?filepath=org/bouncycastle/bcpg-jdk15on/1.67/bcpg-jdk15on-1.67.jar)
* [org.jdom / jdom2](https://search.maven.org/remotecontent?filepath=org/jdom/jdom2/2.0.6/jdom2-2.0.6.jar)
* [org.jpos / jpos](https://search.maven.org/remotecontent?filepath=org/jpos/jpos/2.1.8/jpos-2.1.8.jar)
* [org.bouncycastle / bcprov-jdk15on](https://search.maven.org/remotecontent?filepath=org/bouncycastle/bcprov-jdk15on/1.69/bcprov-jdk15on-1.69.jar)
* [org.bouncycastle / bcpg-jdk15on](https://search.maven.org/remotecontent?filepath=org/bouncycastle/bcpg-jdk15on/1.69/bcpg-jdk15on-1.69.jar)
* [org.jdom / jdom2](https://search.maven.org/remotecontent?filepath=org/jdom/jdom2/2.0.6.1/jdom2-2.0.6.1.jar)
* [org.osgi / org.osgi.core](https://search.maven.org/remotecontent?filepath=org/osgi/org.osgi.core/6.0.0/org.osgi.core-6.0.0.jar)
* [commons-cli / commons-cli](https://search.maven.org/remotecontent?filepath=commons-cli/commons-cli/1.4/commons-cli-1.4.jar)
* [org.yaml / snakeyaml](https://search.maven.org/remotecontent?filepath=org/yaml/snakeyaml/1.26/snakeyaml-1.26.jar)
* [org.yaml / snakeyaml](https://search.maven.org/remotecontent?filepath=org/yaml/snakeyaml/1.33/snakeyaml-1.33.jar)
* [org.hdrhistogram / HdrHistogram](https://search.maven.org/remotecontent?filepath=org/hdrhistogram/HdrHistogram/2.1.12/HdrHistogram-2.1.12.jar)
* [org.javatuples / javatuples](https://search.maven.org/remotecontent?filepath=org/javatuples/javatuples/1.2/javatuples-1.2.jar)
3. Restart JMeter.
Expand All @@ -460,15 +462,17 @@ The following properties control the plugin behaviour:
How long to wait for incoming connections when running in server-mode (default: 1 minute).
- `jmeter.iso8583.channelReconnectDelay` (ms):
May be used to override the Q2 Channel Adaptor default of 10 seconds.
- `jmeter.iso8583.arqcInputTags`:
- `jmeter.iso8583.arqcInputTags` (until v1.2):
Comma-separated list of hexadecimal EMV tag numbers that will be included in the ARQC calculation.
This may be used to include additional (or exclude standard) tags
(default: `9F02,9F03,9F1A,95,5F2A,9A,9C,9F37,82,9F36,9F10`).
- `jmeter.iso8583.arqcFromFullIADForCVNs` (since v1.2):
Note: As of v1.3 this will be handled automatically by the jPOS IAD parser.
- `jmeter.iso8583.arqcFromFullIADForCVNs` (v1.2 only):
Comma-separated list of hexadecimal CVNs (Cryptogram Version Numbers) for which the ARQC calculation
includes the full content of tag `9F10` (Issuer Application Data)
instead of just the CVR (Card Verification Results) portion
(default: `12,16` = CVN18, CVN22).
Note: As of v1.3 this will be handled automatically by the jPOS IAD parser.
- `jmeter.iso8583.binaryFieldTags`:
Comma-separated list of hexadecimal tag numbers that will be interpreted as binary fields,
in addition to binary EMV tags (default: none).
Expand Down Expand Up @@ -532,7 +536,7 @@ Every message field needs an appropriate jPOS Field Packager
(a Java class that translates between the logical and binary value of the message field).
Unfortunately, not all classes are well documented, however, their class names follow a quite consistent naming scheme.

Sometimes, an [existing configuration](https://github.com/jpos/jPOS/tree/v2_1_6/jpos/src/dist/cfg/packager)
Sometimes, an [existing configuration](https://github.com/jpos/jPOS/tree/v2_1_8/jpos/src/dist/cfg/packager)
can be a starting point or even be sufficient for performance testing purposes
(as not all fields need to be correctly defined but only the ones used in the JMeter test).

Expand All @@ -541,7 +545,7 @@ otherwise message traces may have to be inspected and interpreted.

For example, suppose the trace for an 0800 Network Management message starts with the bytes `30 38 30 30` (hexadecimal),
which are the MTI's ASCII representation, then the Field Packager class should be
[`org.jpos.iso.IFA_NUMERIC`](https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/iso/IFA_NUMERIC.java).
[`org.jpos.iso.IFA_NUMERIC`](https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/iso/IFA_NUMERIC.java).
Otherwise, if the trace starts with `08 00` (hex),
i.e. the MTI in [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal), the class should be
[`org.jpos.iso.IFB_NUMERIC`](https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/iso/IFB_NUMERIC.java).
[`org.jpos.iso.IFB_NUMERIC`](https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/iso/IFB_NUMERIC.java).
Binary file modified docs/crypto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@
<dependency>
<groupId>org.jpos</groupId>
<artifactId>jpos</artifactId>
<version>2.1.6</version>
<version>2.1.8</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.67</version>
<version>1.69</version>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand Down
22 changes: 11 additions & 11 deletions src/main/java/nz/co/breakpoint/jmeter/iso8583/ISO8583Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* Advanced, Channel-dependent configuration properties can be specified via name/value pairs.
*
* For example, <i>srcid</i> and <i>dstid</i> for
* <a href="https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/iso/channel/VAPChannel.java#L236-L237">
* <a href="https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/iso/channel/VAPChannel.java#L236-L237">
* VAPChannel's Base1Header</a><br>
* For even more advanced use cases, above XML files may still be used and copied to the Q2 deploy folder.
*/
Expand Down Expand Up @@ -86,9 +86,9 @@ public class ISO8583Config extends ConfigTestElement
}

public enum ConnectionSelection {
LAST, // Last connected https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L349
RR, // Round robin https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L384
ALL; // All connected https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L364
LAST, // Last connected https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L350
RR, // Round robin https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L385
ALL; // All connected https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L365

// Tags must match ResourceBundle and appear in script files:
public static ConnectionSelection fromTag(String connectionSelection) {
Expand Down Expand Up @@ -195,8 +195,8 @@ protected Element addSSLConfig(Element descriptor) {
if (keystore == null || keystore.isEmpty()) return descriptor;

// socketFactory attr vs property
// https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L252
// https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/iso/ChannelAdaptor.java#L467
// https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/iso/QServer.java#L253
// https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/iso/ChannelAdaptor.java#L467
descriptor
.addContent(isServer() ?
new Element("attr")
Expand Down Expand Up @@ -232,7 +232,7 @@ protected Element addRequestListener(Element descriptor) {
}

protected Element getChannelAdaptorDescriptor(String key) {
// https://github.com/jpos/jPOS/blob/v2_1_6/doc/src/asciidoc/ch08/channel_adaptor.adoc
// https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch08/channel_adaptor.adoc
Element descriptor = new Element("channel-adaptor")
.setAttribute("name", getChannelAdaptorName())
.setAttribute("logger", Q2_LOGGER)
Expand All @@ -245,7 +245,7 @@ protected Element getChannelAdaptorDescriptor(String key) {
}

protected Element getOneShotChannelAdaptorDescriptor(String key) {
// https://github.com/jpos/jPOS/blob/v2_1_6/doc/src/asciidoc/ch08/one_shot_channel_adaptor.adoc
// https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch08/one_shot_channel_adaptor.adoc
Element descriptor = new Element("qbean")
.setAttribute("name", getChannelAdaptorName())
.setAttribute("logger", Q2_LOGGER)
Expand Down Expand Up @@ -295,7 +295,7 @@ protected QBeanSupport startQServer() {
return null;
}
// Build QBean deployment descriptor in memory
// https://github.com/jpos/jPOS/blob/v2_1_6/doc/src/asciidoc/ch08/qserver.adoc
// https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch08/qserver.adoc
Element descriptor = new Element("qserver")
.setAttribute("name", getQServerName())
.setAttribute("logger", Q2_LOGGER)
Expand Down Expand Up @@ -325,7 +325,7 @@ protected QBeanSupport startMux() {

// Build QBean deployment descriptor in memory
// (note the in/out queues need to be cross-wired):
// https://github.com/jpos/jPOS/blob/v2_1_6/doc/src/asciidoc/ch08/qmux.adoc
// https://github.com/jpos/jPOS/blob/v2_1_8/doc/src/asciidoc/ch08/qmux.adoc
Element descriptor = new Element("qmux")
.setAttribute("name", getMuxName())
.setAttribute("logger", Q2_LOGGER)
Expand All @@ -351,7 +351,7 @@ protected QBeanSupport startMux() {
}

// Mimic Q2 deployment of a descriptor file, followed by starting the QBean,
// https://github.com/jpos/jPOS/blob/v2_1_6/jpos/src/main/java/org/jpos/q2/Q2.java#L560
// https://github.com/jpos/jPOS/blob/v2_1_8/jpos/src/main/java/org/jpos/q2/Q2.java#L551
// but using more accessible QFactory methods:
protected QBeanSupport deployAndStart(Element descriptor) {
if (log.isDebugEnabled()) {
Expand Down
Loading

0 comments on commit 891826b

Please sign in to comment.