Getting Started with the 3DS SDK
/n software 3-D Secure includes an EMVCo Certified 3DS SDK that can be used to support EMV® 3-D Secure (EMV 3DS) authentication natively in a mobile application. This SDK is built according to the EMV 3DS (versions 2.1.0 and 2.2.0) specification released by EMVCo. This specification, as well as more information on EMV 3DS in general, can be found on the EMV® 3-D Secure website. The following sections provide guidance on getting started with the /n software 3DS SDK.
Demo applications are included with the SDK for both Android and iOS. These communicate with a test server, and can be helpful in seeing the 3DS SDK in action, and how it fits in to a mobile application project.
Contents
- Security Guidance and Best Practices
- 3DS SDK Flow
- Getting Started in Android
- Initializing the SDK
- Creating a Transaction
- Displaying Progress
- Authenticating
- Response Handling
- Performing a Challenge
- Completing Authentication
- Cleanup
- Getting Started in iOS
- Initializing the SDK
- Creating a Transaction
- Displaying Progress
- Authenticating
- Response Handling
- Performing a Challenge
- Completing Authentication
- Cleanup
- Managing Resources
- Notes on Application Permissions
Security Guidance and Best Practices
Before starting development using the 3DS SDK, it is important to consider the security implications, and how to best protect sensitive data. While the SDK takes care of many security functions, as detailed in the EMVCo 3DS SDK specification, there are other considerations that need to be taken into account.
Communication with the 3DS Server
While communication with the 3DS Server is outside the scope of the 3DS SDK itself, the data transmitted, both generated from the 3DS SDK and otherwise, should be properly secured according to payment system security standards. Annex D of the EMVCo Protocol and Core Functions Specification provides guidance that has been summarized below. These standards would be appropriate for communication between the 3DS SDK and 3DS Server:
TLS 1.2 or higher should be used, with key lengths as follows:
- RSA: 2048 bits or longer.
- ECC: 256 bits or longer.
One of the following cipher suites should be used:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
Curve P-256 shall be used and indicated in the cipher suite extension.
Protection of Sensitive Cardholder Data
Much of the data used for authentication is outside the scope of the 3DS SDK, and is transmitted to the 3DS Server outside of any authentication parameters. This sensitive data includes anything from the card number itself to cardholder contact details.
Protection includes the above secure transmission, as well as protection on the device itself. This may include either not saving the data locally, or encrypting it properly if stored.
Cleanup the ThreeDS2Service Instance
Make sure to cleanup the SDK after you are finished with 3-D Secure. This can be done using the cleanup method like so:
// ...
ThreeDS2Service.INSTANCE.cleanup(applicationContext);
Versioning
The 3DS SDK version is formatted as a.b.cccc, where a is the major version, b is the minor version, and cccc is the build number. Using 2.2.7941 as an example, the major version is 2, the minor version is 2, and the build number is 7941. The build number increments every day starting from a base date of January 1st, 2000. The version can be retrieved at runtime using the ThreeDS2Service object's getSDKVersion method.
Issue Reporting
Vulnerabilities and issues can be reported to our support team via email at support@nsoftware.com. When contacting us, please do not include sensitive data including, but not limited to, credit card account numbers or private customer data. If necessary, we can provide a link for secure sharing of sensitive information.
Updates
Updates to the 3DS SDK are made available on our website. Builds there are updated periodically, as well as when critical security updates are made. When the builds are updated, an email notification will be sent out to email addresses used when ordering, or addresses manually added to our list here.
No updates are pushed directly to deployed applications. It would instead be required to obtain the latest builds and integrate it them into the application. When updating, care should be taken to ensure the integrity of transactions already in progress.
Security Updates
The Security Checks sections below contain details on the security checks performed during initialization of the SDK, as well as checks made periodically at runtime. The guidance in that section should be followed to make sure your application knows about these issues, and responds accordingly.
3DS SDK Flow
Below is a general overview of the sequence of 3DS SDK calls required to progress through 3-D Secure authentication. The solid lines represent active 3DS SDK functionality, while dotted lines represent behavior outside of the 3DS SDK itself.
Getting Started in Android
To begin add the ipworks3ds_sdk.aar to your app:
- Copy the ipworks3ds_sdk.aar to the /libs folder in your module.
- Import the SDK by adding this line to your module build.gradle file:
implementation(name: 'ipworks3ds_sdk', ext: 'aar')
There are two versions of the 3DS SDK included with the installation: one to be used for development and one for production. The production version includes more strict security measures that would not allow for common development processes to occur, including running with attached debuggers or using simulators/emulators. The deployment version includes _deploy in the filename.
PCI 3DS SDK imposes requirements on 3DS SDKs that severly restrict development. For example, running on an emulator or debugging are forbidden in a production 3DS SDK. As such, the /n software 3DS SDKs include both development and deployment versions, with the main differences being related to the security checks performed and resulting behavior. More details can be found in the Security Checks section.
Initializing the SDK
Depending on the 3DS Requestor application implementation, a ThreeDS2Service instance is created either during startup of the 3DS Requestor app (as a background task), or when a transaction is initiated. The state of the service is maintained until the cleanup method is called. To create an instance of the ThreeDS2Service, call the initialize method like so:
ThreeDS2Service.INSTANCE.initialize(getApplicationContext()),
configParameters,
locale,
uiCustomization,
new MyClientEventListener(),
new MySecurityEventListener());
The parameters this initialize method takes are as follows:
Name | Type | Description |
---|---|---|
applicationContext | Context | An instance of the Android application context. Use the getApplicationContext activity method if necessary. |
configParameters | ConfigParameters | Configuration information that shall be used during initialization. For details, see the ConfigParameters section. |
locale | String | A string that represents the locale for the app's user interface (e.g. "en-US"). For future use. |
uiCustomization | UiCustomization | A class that allows the customization of the 3DS SDK UI elements (fonts, colors, etc.). For details, see the UiCustomization section. |
clientEventListener | ClientEventListener | A listener to receive SDK events (for logging, etc.) For details, see the ClientEventListener section. |
securityEventListener | SecurityEventListener | A listener to receive security warning events raised during SDK initialization and during runtime. For details, see the SecurityEventListener section. |
Config Parameters
The ConfigParameters class is used to provide details required by the 3DS SDK for initialization. The ConfigParameters.Builder class helps with organizing these parameters which can be used as follows:
List directoryServerInfoList = new ArrayList<>();
directoryServerInfoList.add(new ConfigParameters.DirectoryServerInfo(DSInfo.TEST_DS_ID, DSInfo.TEST_DS_CERT, DSInfo.TEST_DS_CA));
List deviceParameterBlacklist = new ArrayList<>();
deviceParameterBlacklist.add("A009");
deviceParameterBlacklist.add("A010");
List maliciousApps = new ArrayList<>();
maliciousApps.add("de.robv.android.xposed");
List trustedAppStores = new ArrayList<>();
trustedAppStores.add("com.xiaomi.market");
String appsignature = ParseAppSignature(HTTP.Get("https://www.example.com/signature"));
List clientConfigs = new ArrayList<>();
clientConfigs.add("logLevel=3");
clientConfigs.add("MaskSensitive=false");
ConfigParameters configParameters = new ConfigParameters.Builder(directoryServerInfoList, runtimeLicense)
.deviceParameterBlacklist(deviceParameterBlacklist)
.maliciousApps(maliciousApps)
.trustedAppStores(trustedAppStores)
.appSignature(appsignature)
.clientConfig(clientConfigs)
.OOBAppURLSupported(true)
.build();
Parameters fall into a few groups:
Name | Type | Description |
---|---|---|
DirectoryServerInfo | List<DirectoryServerInfo> | Used to specify encryption keys and certificates for various supported directory servers. More details can be found in the DirectoryServerInfo section. |
RuntimeLicense | String | The 3DS SDK license string. |
DeviceParameterBlacklist | List<String> | A list of device parameters NOT to pull from the device. By default, the SDK will pull as many device parameters as it can. This setting group can be used to instruct the SDK not to pull certain parameters. You can add parameters to this list by specifying the identifier. A full list of parameters can be found in the EMV® 3-D Secure SDK Device Information document, which can be obtained from EMVCo directly. |
MaliciousApps | List<String> | Apps that are recognized as malicious. If the apps are installed, a security warning (SW02) will be raised. The following apps are considered malicious by default:
|
TrustedAppStores | List<String> | A security warning (SW02) will be raised if the app is not installed from a trusted app store. By default, the Google Play Store (com.android.vending) is trusted. This parameter can be used to specify additional trusted app stores. |
AppSignature | List<String> | A security warning (SW02) is raised if this value does not match the app signature. This property should be set to the SHA256 fingerprint of the certificate used to sign the app. If this value is not specified, the SDK will see the signature as invalid. Note that this value should not be hardcoded in the app for security reasons. Instead, the fingerprint should be stored on a server, retrieved at runtime, and set here. |
ClientConfig | List<String> | Configuration settings used for additional configuration of the SDK. A list of available options can be found in the ClientConfig section. |
After building the ConfigParameters object, the addParams method can be used to add additional parameters. This method accepts a group, parameter name, and parameter value. There are no specific groups associated with the SDK at this time, so the group can be set to a null value. For example:
configParameters.addParam(null, "ParameterName", "ParameterValue");
Available additional parameters are as follows:
Name | Description |
---|---|
ShowWhiteBoxInProcessingScreen | Display a white box behind the processing icon and directory server image. This takes a boolean string value ("True" or "False"). |
UseDefaultTrustedAppStoreList | This setting controls whether the default trusted app store list (i.e. com.android.vending) is used. This is true by default, but when set to false only those stores explicitly specified via the TrustedAppStores list during initialization will be trusted. This takes a boolean string value ("True" or "False"). |
ProgressBarColor | This setting controls the color of the progress bar displayed in the progress dialog returned by the getProgressView method. This accepts a hex color code value (e.g. "#b884f2"). |
UI Customization
The UICustomization class exposes functionality to customize the 3DS SDK UI elements. This allows the 3DS Requestor application to have its own look-and-feel in the native challenge pages. The customization of Buttons, Labels, TextBoxes, and Toolbars is enabled via the various classes and subclasses outlined below.
UICustomization
Main class for configuring the customization of UI elements.
public class UiCustomization {
enum ButtonType (VERIFY, CONTINUE, NEXT, CANCEL, RESEND)
enum UICustomizationType (DEFAULT, DARK, MONOCHROME)
enum LabelType (INFO_HEADER, INFO_TEXT, INFO_LABEL, WHITELIST, WHY_INFO, WHY_INFO_TEXT, EXPANDABLE_INFO,
EXPANDABLE_INFO_TEXT, SELECTION_LIST, DATA_ENTRY_LABEL, DATA_ENTRY_LABEL_2)
void setButtonCustomization(ButtonCustomization buttonCustomization, ButtonType buttonType)
void setToolbarCustomization(ToolbarCustomization toolbarCustomization)
void setLabelCustomization(LabelCustomization labelCustomization)
void setTextBoxCustomization(TextBoxCustomization textboxCustomization)
void setBackground(String hexColorCode)
void setInformationZoneIconPosition(int position) // 0: right, 1: left, 2: hide
ButtonCustomization getButtonCustomization(ButtonType buttonType)
ToolbarCustomization getToolbarCustomization()
LabelCustomization getLabelCustomization()
TextBoxCustomization getTextBoxCustomization()
TextBoxCustomization getTextBoxTwoCustomization()
String getBackground(String hexColorCode)
int getInformationZoneIconPosition(int position)
}
ButtonCustomization
The ButtonCustomization class enables the customization of various buttons presented to the cardholder during the challange process.
public class ButtonCustomization {
void setBackgroundColor(String hexColorCode)
void setCornerRadius(int cornerRadius)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
void setTextColor(String hexColorCode)
void setHeight(int pixels)
void setPadding(int start, int top, int end, int bottom) // applicable only for ButtonType of CANCEL
String getBackgroundColor()
int getCornerRadius()
String getTextFontName()
int getTextFontSize()
String getTextColor()
int getHeight()
int[] getPadding() // applicable only for ButtonType of CANCEL
}
For example, the following code will configure buttons with red backgrounds and white font:
UiCustomization uiCustomization = new UiCustomization();
ButtonCustomization customButton = new ButtonCustomization();
customButton.setTextColor("#FFFFFF"); // White
customButton.setBackgroundColor("#951728"); // Dark red
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.CANCEL);
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.CONTINUE);
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.NEXT);
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.RESEND);
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.SUBMIT);
This results in the following Submit button for a Single-Select challenge:
LabelCustomization
The LabelCustomization class enables the customization of various labels displayed throughout the challenge process.
public class LabelCustomization {
void setHeadingTextAlignment(int textAlignment)
void setHeadingTextColor(String hexColorCode)
void setHeadingTextFontName(String fontName)
void setHeadingTextFontSize(int fontSize)
void setInputTextColor(String hexColorCode)
void setInputTextFontName(String fontName)
void setInputTextFontSize(int fontSize)
void setTextColor(String hexColorCode)
void setTextColor(LabelType labelType, String hexColorCode)
void setTextFontName(String fontName)
void setTextFontName(LabelType labelType, String fontName)
void setTextFontSize(int fontSize)
void setTextFontSize(LabelType, labelType, int fontSize)
void setBackgroundColor(LabelType labelType, String hexColorCode)
void setPadding(LabelType labelType, int start, int top, int end, int bottom)
int getHeadingTextAlignment()
String getHeadingTextColor()
String getHeadingTextFontName()
int getHeadingTextFontSize()
String getInputLabelTextColor()
String getInputLabelTextFontName()
int getInputLabelTextFontSize()
String getTextColor()
String getTextColor(LabelType labelType)
String getTextFontName()
String getTextFontName(LabelType labelType)
int getTextFontSize()
int getTextFontSize(LabelType labelType)
String getBackgroundColor(LabelType labelType)
int[] getPadding(LabelType labelType)
}
TextBoxCustomization
The TextBoxCustomization class enables the customization of textboxes displayed throughout the challenge process.
public class TextBoxCustomization {
void setBorderColor(String hexColorCode)
void setBorderWidth(int borderWidth)
void setCornerRadius(int cornerRadius)
void setTextColor(String hexColorCode)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
String getBorderColor()
int getBorderWidth()
int getCornerRadius()
String getTextColor()
String getTextFontName()
int getTextFontSize()
}
ToolbarCustomization
The ToolbarCustomization class enables the customization of the toolbar displayed throughout the challenge process.
public class ToolbarCustomization {
void setBackgroundColor(String hexColorCode)
void setButtonText(String buttonText)
void setHeaderText(String headerText)
void setTextColor(String hexColorCode)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
String getBackgroundColor()
String getButtonText()
String getHeaderText()
String getTextColor()
String getTextFontName()
int getTextFontSize()
}
Icon Customization
Along with the customization of the look-and-feel of the UI via the UiCustomization class detailed above, it may be desirable to also customize the images utilized by the SDK. There are three images used by the Android SDK for this, and they can be customized by including files with the exact names listed below in the drawable resources section of the project:
- ipworks3ds_expand_section_indicator: The icon used to indicate a section that can be expanded.
- ipworks3ds_collapse_section_indicator: The icon used to indicate a section that can be collapsed.
- ipworks3ds_warning_indicator: The icon used (as indicated by the ACS) to draw attention to challenge information text being displayed.
- ipworks3ds_ds_DSID: The directory server logo shown when the progress dialog is displayed during communication with the 3DS Server. The DSID is the lowercase directory server ID matching one configured via a DirectoryServerInfo parameter. The logo displayed by the progress dialog will be selected based on the directory server ID used when creating a transaction.
If these images are included in the project, the SDK will use them automatically; no additional code or configuration is required.
ClientEventListener
The ClientEventListener object exposes a number of events that are fired at certain points during the SDK's operation. Below is a list of the available events:
DataPacketIn
Fired when receiving a data packet from the server.
public class MyClientEventListener implements ClientEventListener {
...
public void fireDataPacketIn(byte[] dataPacket) {
Log.i("ClientDataPacketIn", new String(dataPacket));
}
...
}
This event fires when a packet is received. The entire data packet (including all framing and error detection characters) is contained in the dataPacket parameter. This parameter may be inspected for advanced troubleshooting, or to extract additional response properties beyond the scope of this component.
DataPacketOut
Fired when sending a data packet to the server.
public class MyClientEventListener implements ClientEventListener {
...
public void fireDataPacketOut(byte[] dataPacket) {
Log.i("ClientDataPacketOut", new String(dataPacket));
}
...
}
This event fires right before each data packet is sent. The entire data packet (including all framing and error detection characters) is contained in the dataPacket parameter. This parameter may be inspected for advanced troubleshooting.
Log
Fires once for each log message.
public class MyClientEventListener implements ClientEventListener {
...
public void fireLog(int logLevel, String message, String logType) {
Log.i("ClientLog", logType + " - " + message);
}
...
}
Logging is handled through the Log event. This will fire any time a message is built or a response is parsed, including error messages.
When the Log event is fired, the message in question is made available via the message event parameter. The other event arguments are logType and logLevel.
The logType parameter indicates the type of the log entry. Possible values are:
- Info
- RequestHeaders
- ResponseHeaders
- RequestBody
- ResponseBody
- ProxyRequest
- ProxyResponse
- FirewallRequest
- FirewallResponse
- CReq
- CRes
- Erro
- EphemeralKey
- DeviceParams
- SW
A logType of SW indicates a Security Warning. When this value is present, the message parameter will contain a code to indicate a more specific cause of the warning. Below is a list of possible warning message values:
SW Message Value | Description |
---|---|
01 | Tampered, not installed from a trusted store |
02 | Tampered; internal error checking app store |
03 | Tampered; invalid appSignature |
04 | Tampered; suspicious app installed |
05 | Root; suspicious files present |
06 | Root; suspicious apk present |
07 | Root; root permissions |
08 | Root; root tag |
09 | Root; hooked |
10 | Debugging; debugger attached |
The logLevel parameter in the event indicates the log level to which the current message belongs. Possible values are:
- 0 (None) No events are logged.
- 1 (Info - default) Informational events are logged.
- 2 (Verbose) Detailed data is logged.
- 3 (Debug) Debug data is logged.
Info level logs are available by default. The LogLevel configuration setting, specified in the Client Config settings, can be used to instruct the SDK to raise more or less detailed logs.
It is recommended to output all messages raised in this event to a file for record keeping purposes, or for later debugging issues that may have come up.
SSLServerAuthentication
Fired after the server presents its certificate to the client.
public class MyClientEventListener implements ClientEventListener {
...
public void fireSSLServerAuthentication(byte[] certEncoded, String certSubject, String certIssuer, String status, boolean[] accept) {
//...
}
...
}
This event is where the client can decide whether to continue with the connection process or not. The accept parameter is a recommendation on whether to continue or close the connection. This is just a suggestion: application software must use its own logic to determine whether to continue or not.
When accept is False, status shows why the verification failed (otherwise, status contains the string "OK"). If it is decided to continue, you can override and accept the certificate by setting the accept parameter to True.
SSLStatus
Shows the progress of the secure connection.
public class MyClientEventListener implements ClientEventListener {
...
public void fireSSLStatus(String message) {
Log.i("ClientSSLStatus", message);
}
...
}
The event is fired for informational and logging purposes only. Used to track the progress of the connection.
SecurityEventListener
The SecurityEventListener class exposes a way to be notified of security issues that occur both during initialization of the SDK and at runtime. This is done via a single alarm event:
Alarm
Fired when a security issue is detected.
public class MySecurityEventListener implements SecurityEventListener {
...
public void alarm(Severity severity, SecurityEvent event) {
TransactionManager.getInstance().showToast("[Security Alarm] Severity: " + severity + ", Event: " + event);
}
...
}
If a security issue is detected, the Alarm event will be raised. The severity of the error will be indicated by the severity event parameter. Possible values are:
- LOW
- MEDIUM
- HIGH
The event parameter will indicate which issue was encountered. Possible values are:
- ROOT
- TAMPERED
- INSTALLED_FROM_UNTRUSTED_STORE
- HOOK
- EMULATOR
- DEBUGGING
- DEBUG_ENABLED
For more information on the security checks performed by the component, and recommendations on handling detected issues, see the Security Checks section below.
DirectoryServerInfo
DirectoryServerInfo parameters are used to specify certificate details for the various supported directory servers (DS). When creating a Transaction, the DS_ID is used to specify the certificates to be used for that transaction. Each DirectoryServerInfo consists of three pieces of information:
- DS_ID An identifier used internally in the SDK to match the transaction with a particular DS. Also referred to as an RID.
- DS_CERT Encryption certificate provided by the DS. Used to encrypt the DeviceInfo and generate keys to use for Challenge security.
- DS_CA_CERT The root CA certificate used to issue the DS_CERT. This is used to verify the signature on the response from the DS (ARes packet), and can include the intermediate certificate as well.
Preconfigured Certificates
The 3DS SDK comes preconfigured with certificates for the following Directory Servers. To use these certificates, simply pass one of the DS ID values below when creating the Transaction.
Card Scheme | RID | KID | DS CERT | DS CA CERT(S) |
---|---|---|---|---|
Visa | A000000003 | 747da056-476c-4296-a7c4-7e853e235ef0 | CN=3ds2.rsa.encryption.visa.com Expires: 2027-02-26 | CN=Visa Public RSA Root CA CN=Visa eCommerce Root CA - G2 CN=Visa eCommerce Issuing CA - G2 |
MasterCard | A000000004 | 116f90eee124062e2ca9c8efeb54802c34d963a0 | CN=3ds2.directory.mastercard.com Expires: 2026-07-15 | CN=PRD MasterCard Identity Check Root CA |
Amex | A000000025 | CN=sdk.safekey.encryptkey.com Expires: 2025-05-23 | CN=American Express Private Certification Authority | |
Discover | A000000152 | CN=Discover SDK Expires: 2027-03-07 | CN=extendedroot.protectbuy.com | |
JCB | A000000065 | CN=ds2apr.jcb-tds.com Expires: 2051-03-02 | CN=JCB DS Root CA EMV 3-D Secure | |
UnionPay | A000000333 | CN=CFCA@UnionPay International@N9131000005455878X6@1 Expires: 2025-07-08 | CN=CFCA ACS CA |
Client Config
The SDK accepts one or more of the following configuration settings. These are set as SETTING=VALUE pairs, and set as the clientConfig when building the ConfigParameters.
LogLevel
This config specifies the level of logging enabled in the component. Possible values include:
0 (None) | No events are logged. |
1 (Info - default) | Informational events are logged. |
2 (Verbose) | Detailed data is logged. |
3 (Debug) | Debug data is logged. |
This is set to 1 (Info) by default.
MaskSensitive
This setting controls whether sensitive data is masked in the Log event. When set to True (default) the card number value will be replaced with the value *************.
Note: DataPacketOut will always contain the raw unmasked value regardless of this setting. This setting only applies to the Log event.
The default value is True.
Security Checks
The SDK performs security checks and collects device information during initialization. Warnings produced during the 3DS SDK initialization process can be retrieved using the getWarnings method, which returns a list of Warning objects. These can be checked by the app to determine whether or not to proceed with the checkout process:
/* check warnings */
List warnings = ThreeDS2Service.INSTANCE.getWarnings();
if (warnings.size() > 0) {
// process warnings
// abort the checkout if necessary
}
The Warning object consists of the following fields:
Name | Type | Description |
---|---|---|
id | String | Warning identifier. |
message | String | Warning message. |
severity | Severity (enum) | Warning severity level (LOW, MEDIUM, HIGH). |
The following warnings are documented in the EMVCo specification:
Security Warning ID | Description | Severity Level |
---|---|---|
SW01 | The device is jailbroken. | HIGH |
SW02 | The integrity of the SDK has been tampered. | HIGH |
SW03 | An emulator is being used to run the app. | HIGH |
SW04 | A debugger is attached to the app. | MEDIUM |
SW05 | The OS or the OS version is not supported. | HIGH |
To be notified of security issues both at initialization and at runtime, it is recommended to use the SecurityEventListener as well.
Security Checks Performed During Initialization
The following security checks are performed during initialization of the SDK:
- Root detection: several ways of detecting if the device is rooted
- SDK tampering detection: including app signer fingerprint validation, hook detection, and malicious app detection
- Checks to make sure the app was installed from trusted app stores
- Emulator detection
- Detection of an attached debugger
- OS version detection
These initialization checks result in warnings accessible via the getWarnings detailed above. The message will contain a description of the issue encountered.
Security Checks Performed at Runtime
The following security checks are performed at runtime:
- Emulator detection (high severity): during Transaction.getAuthenticationRequestParameters()
- Debugging detection (medium severity): during Transaction.doChallenge()
- Root detection (high severity): during Transaction.doChallenge()
- Hook detection (high severity): during ThreeDS2Service.createTransaction(), and during the challenge process when the Submit/Resend/Cancel buttons are clicked
- Debug enabled detection (low severity): during Transaction.doChallenge()
These runtime checks result in firing of the Security Event Listener alarm event, and the activity closing for high severity issues. In the development version of the SDK (without _deploy in the file name), these checks are not performed.
Creating a Transaction
Call the createTransaction method to start a transaction. A reference should be kept for this transaction throughout the entire 3-D Secure process. This method takes the directory server ID, which points to a DirectoryServerInfo configuration parameter added during SDK initialization. The second parameter is a protocol version as a string. Supported version strings are 2.1.0 and 2.2.0.
sdkTransaction = ThreeDS2Service.INSTANCE.createTransaction(DSInfo.TEST_DS_ID, "2.2.0");
Later, when the transaction is complete, it should be closed via the Transaction object's close method.
Displaying Progress
A progress dialog must be displayed to the end user at certain points in the 3-D Secure process. While performing the challenge, the 3DS SDK will automatically display a progress dialog when appropriate.
A progress dialog must also be displayed to the user while the application is communicating with the 3DS Server and waiting for the authentication request results. The dialog used by the 3DS SDK is available to be used by the application if desired, and can be obtained from the Transaction object via the getProgressView method like so:
// The progress dialog is an instance of android.app.ProgressDialog
ProgressDialog sdkProgressDialog;
// Retrieve the progress dialog from the transaction object instance
sdkProgressDialog = sdkTransaction.getProgressView(mActivity);
sdkProgressDialog.show();
// Later, to hide/dismiss:
sdkProgressDialog.dismiss();
The 3DS SDK will automatically hide the dialog when starting the challenge process, so there is no need to explicitly dismiss the dialog in the application code.
Authenticating
The authentication process starts with a call to the Transaction object's getAuthenticationRequestParameters method. When this method is called, the 3DS SDK will encrypt the device information it collected during initialization and make it, along with other SDK information required by the 3DS Server, available in the returned AuthenticationRequestParameters object. This AuthenticationRequestParameters object consists of the following fields:
Name | Description |
---|---|
SDKTransactionId | A transaction identifier randomly generated by the SDK. |
DeviceData | Device data collected by the SDK during initialization and encrypted using the DS key. |
SDKEphemeralPublicKey | The public key component of the ephemeral key pair generated by the SDK. |
SDKAppId | A UUID value, generated by the 3DS SDK, that uniquely identifies the app on the device. |
SDKReferenceNumber | Assigned to our SDK by EMVCo after certification. |
MessageVersion | From createTransaction, or a default value from the SDK (2.1.0). |
AuthRequest | Packaged authentication request data to be sent to the 3DS Server. |
The AuthRequest property is a packaged form of the other properties. The app would transmit this to the 3DS Server via a communication channel outside the scope of the 3DS SDK itself. On the server side, this AuthRequest data is designed to be passed directly in to the 3DS Server component's ClientAuthRequest property prior to sending the authentication request to the directory server via its SendAuthRequest method.
When the SendAuthRequest method completes, the Server component's ClientAuthResponse property will contain data that can be sent back to the app and passed to the 3DS SDK to use if a challenge is required.
Response Handling
The 3DS Server is responsible for reading the authentication response from the directory server and indicating to the client (in this case, the app) whether or not a challenge is required. In our 3DS Server component, check the TransactionStatus property after the SendAuthRequest method completes. If this is a value of C or D, a challenge is required.
If no challenge is required (frictionless flow), or authentication cannot be performed for some reason, no further action is required from a 3-D Secure standpoint. Proceed to the Completing Authentication section for details on closing the transaction.
If a challenge is required, the 3DS Server should return the ClientAuthResponse property value to the app for use when starting the challenge process. The Performing a Challenge section details how to perform the challenge.
Performing a Challenge
If a challenge is required, the challenge is performed by creating the ChallengeParameters (using the ClientAuthResponse from the 3DS Server component) and calling the doChallenge method. The SDK will take care of all communication with the ACS while performing the challenge, as well as prompting the user as needed for the required input. When the challenge process is complete, the relevant ChallengeStatusReceiver callback method will fire.
Challenge Status Receiver
ChallengeStatusReceiver is an interface that should be implemented in the application and passed to the doChallenge method when Starting the Challenge. When the challenge process has finished, either successfully or in error, one of the following corresponding methods will be called:
Name | Description |
---|---|
completed | Called when the challenge process (that is, the transaction) is completed. When a transaction is completed, a transaction status shall be available. |
cancelled | Called when the cardholder selects the option to cancel the transaction on the challenge screen. |
timedout | Called when the challenge process reaches or exceeds the timeout interval that is specified during the doChallenge call. |
protocolError | Called when the 3DS SDK receives an EMV 3DS protocol-defined error message from the ACS. |
runtimeError | Called when the 3DS SDK encounters errors during the challenge process. These errors include all errors except those covered by the protocolError method. |
Example implementations of these methods can be found below:
@Override
public void completed(CompletionEvent completionEvent) {
showToast("Challenge completed with transactionStatus " + completionEvent.getTransactionStatus());
closeTransaction();
}
@Override
public void cancelled() {
showToast("Challenge cancelled.");
closeTransaction();
}
@Override
public void timedout() {
showToast("Challenge timed out.");
closeTransaction();
}
@Override
public void protocolError(ProtocolErrorEvent protocolErrorEvent) {
showToast("Challenge protocolError: " +
protocolErrorEvent.getErrorMessage().getErrorDescription() + "\t" +
protocolErrorEvent.getErrorMessage().getErrorDetails());
closeTransaction();
}
@Override
public void runtimeError(RuntimeErrorEvent runtimeErrorEvent) {
showToast("Challenge runtimeError: " + runtimeErrorEvent.getErrorMessage());
closeTransaction();
}
// Helper method
public void closeTransaction() {
if (sdkTransaction != null) {
sdkTransaction.close();
sdkTransaction = null;
}
sdkProgressDialog = null;
}
Challenge Parameters
The ChallengeParameters class holds parameters that are required to conduct the challenge process. This is passed to the doChallenge method when Starting the Challenge. Available properties, accessible via getters and setters, are:
Name | Type | Description |
---|---|---|
3DSServerTransactionID | String | 3DS Server Transaction ID. |
AcsTransactionID | String | ACS Transaction ID. |
AcsRefNumber | String | ACS Reference Number. |
AcsSignedContent | String | ACS signed content. This data includes the ACS URL, ACS ephemeral public key, and SDK ephemeral public key. |
ThreeDSRequestorAppURL | String | 3DS Requestor App URL. |
ThreeDSServerAuthResponse | String | The Authentication Response from the 3DS Server component. |
These properties can be set individually based on what comes back from the 3DS Server. If using the 3DS Server component, the ThreeDSServerAuthResponse can be set to the generated ClientAuthResponse value, and the other properties will be set automatically based on this value.
ChallengeParameters challengeParameters = new ChallengeParameters();
challengeParameters.setThreeDSServerAuthResponse(authResponse);
Starting the Challenge
If the response from the 3DS Server indicates that a challenge is required, the challenge process is initiated using the doChallenge method. When this is called, control of the UI is handed over to the 3DS SDK. The challenge will be performed by the SDK, and when finished the appropriate ChallengeStatusReceiver event will fire (completed, cancelled, etc.)
sdkTransaction.doChallenge(currentActivity, challengeParameters, this, 5);
The doChallenge method takes the following parameters:
Name | Type | Description |
---|---|---|
currentActivity | android.app.Activity | The activity used by the SDK for the challenge process. |
challengeParameters | ChallengeParameters | ACS details required by the 3DS SDK to conduct the challenge process during the transaction. For details, see the ChallengeParameters section. |
challengeStatusReceiver | ChallengeStatusReceiver | Callback object for notifying the 3DS Requestor App about the challenge status. For details, see the ChallengeStatusReceiver section. |
timeout | Integer | Timeout interval (in minutes) within which the challenge process must be completed. The minimum timeout interval is 5 minutes. |
Completing Authentication
If the completed callback fires, the CompletionEvent parameter will contain more details on the authentication results. This has two properties: sdkTransactionID, and transactionStatus. The transactionStatus contains the transStatus from the last CRes packet, which would be one of the values below:
- Y: Order completed successfully / Authentication successful
- A: Order completed successfully / Attempts processing performed
- N: Order denied / Not authenticated (denied)
- R: Order denied / Authentication rejected
- U: Order failed due to technical reasons / Authentication could not be performed
Cleanup
The cleanup method frees up resources that are used by the 3DS SDK. It is called only once during a single 3DS Requestor App session:
ThreeDS2Service.INSTANCE.cleanup(applicationContext);
Getting Started in iOS
First, the framework will need to be referenced in the project. To do this, drag the .xcframework into the Frameworks section of the project settings.
There are two versions of the 3DS SDK included with the installation: one to be used for development and one for production. The production version includes more strict security measures that would not allow for common development processes to occur, including running with attached debuggers or using simulators/emulators. The deployment version includes _deploy in the filename.
PCI 3DS SDK imposes requirements on 3DS SDKs that severly restrict development. For example, running on an emulator or debugging are forbidden in a production 3DS SDK. As such, the /n software 3DS SDKs include both development and deployment versions, with the main differences being related to the security checks performed and resulting behavior. More details can be found in the Security Checks section.
Initializing the SDK
Depending on the 3DS Requestor application implementation, a ThreeDS2Service instance is created either during startup of the 3DS Requestor app (as a background task), or when a transaction is initiated. The state of the service is maintained until the cleanup method is called. To create an instance of the ThreeDS2Service call the initialize method like so:
try threeDS2Service.initialize(
configParameters: configParameters,
locale: nil,
uiCustomization: uiCustom,
clientEventListener: clientEventListener)
The parameters this initialize method takes are as follows:
Name | Type | Description |
---|---|---|
configParameters | ConfigParameters | Configuration information that shall be used during initialization. For details, see the ConfigParameters section. |
locale | String | A string that represents the locale for the app's user interface (e.g. "en-US"). For future use. |
uiCustomization | UiCustomization | A class that allows the customization of the 3DS SDK UI elements (fonts, colors, etc.). For details, see the UiCustomization section. |
clientEventListener | ClientEventListener | A listener to receive SDK events (for logging, etc.) For details, see the ClientEventListener section. |
securityEventListener | SecurityEventListener | A listener to receive security warning events raised during SDK initialization and during runtime. For details, see the SecurityEventListener section. |
Config Parameters
The ConfigParameters class is used to provide details required by the 3DS SDK for initialization. The ConfigParametersBuilder class helps with organizing these parameters which can be used as follows:
var directoryServerInfoList = [DirectoryServerInfo]()
directoryServerInfoList.append(DirectoryServerInfo(RID: DSInfo.TEST_DS_ID, publicKey: DSInfo.TEST_DS_CERT, CA: DSInfo.TEST_DS_CA))
let deviceParameterBlacklist = ["C005", "I010"]
let clientConfigs = ["LogLevel=3", "MaskSensitive=false"]
let builder = ConfigParametersBuilder.init(directoryServerInfoList: directoryServerInfoList, runtimeLicense: "", deviceParameterBlacklist: deviceParameterBlacklist, clientConfig: clientConfigs, appBundleId: appBundleId)
let configParameters = try builder.build()
Parameters fall into a few groups:
Name | Type | Description |
---|---|---|
DirectoryServerInfo | List<DirectoryServerInfo> | Used to specify encryption keys and certificates for various supported directory servers. More details can be found in the DirectoryServerInfo |
RuntimeLicense | String | The 3DS SDK license string. |
DeviceParameterBlacklist | List<String> | A list of device parameters NOT to pull from the device. By default, the SDK will pull as many device parameters as it can. This setting group can be used to instruct the SDK not to pull certain parameters. You can add parameters to this list by specifying the identifier. A full list of parameters can be found in the EMV® 3-D Secure SDK Device Information document, which can be obtained from EMVCo directly. |
ClientConfig | List<String> | Configuration settings used for additional configuration of the SDK. A list of available options can be found in the Client Config section. |
AppBundleID | String | The expected bundle identifier for the application. This should match the Bundle Identifier identity setting specified when building the application. A security warning is raised if this value does not match the Bundle ID of the application at runtime. If this value is not specified, the SDK will see the Bundle ID as invalid. Note that this value should not be hardcoded in the app for security reasons. Instead, the Bundle ID should be stored on a server, retrieved at runtime, and set here. |
After building the ConfigParameters object, the addParams method can be used to add additional parameters. This method accepts a group, parameter name, and parameter value. There are no specific groups associated with the SDK at this time, so the group can be set to a null value. For example:
try configParameters.addParam(group: nil, paramName: "ParameterName", paramValue: "ParameterValue")
Available additional parameters are as follows:
Name | Description |
---|---|
ShowWhiteBoxInProcessingScreen | Display a white box behind the processing icon and directory server image. This takes a boolean string value ("True" or "False"). |
FireChallengeStatusFirst | This setting allows configuration of when the completed, cancelled, and protocolError Challenge Status Receiver events fire. By default ("False") these will fire after the challenge UI is closed. Setting this to "True" will cause these events to fire before the challenge UI closes. |
UI Customization
The UICustomization class exposes functionality to customize the 3DS SDK UI elements. This allows the 3DS Requestor application to have its own look-and-feel in the native challenge pages. The customization of Buttons, Labels, TextBoxes, and Toolbars is enabled via the various classes and subclasses below.
UICustomization
Main class for configuring the customization of UI elements.
public class UiCustomization {
enum ButtonType (VERIFY, CONTINUE, NEXT, CANCEL, RESEND)
enum UICustomizationType (DEFAULT, DARK, MONOCHROME)
enum LabelType (INFO_HEADER, INFO_TEXT, INFO_LABEL, WHITELIST, WHY_INFO, WHY_INFO_TEXT, EXPANDABLE_INFO,
EXPANDABLE_INFO_TEXT, SELECTION_LIST, DATA_ENTRY_LABEL, DATA_ENTRY_LABEL_2)
void setButtonCustomization(ButtonCustomization buttonCustomization, ButtonType buttonType)
void setToolbarCustomization(ToolbarCustomization toolbarCustomization)
void setLabelCustomization(LabelCustomization labelCustomization)
void setTextBoxCustomization(TextBoxCustomization textboxCustomization)
void setBackground(UIColor color)
void setInformationZoneIconPosition(int position) // 0: right, 1: left, 2: hide
void setBrandingZoneLogoGap(CGFloat value)
ButtonCustomization getButtonCustomization(ButtonType buttonType)
ToolbarCustomization getToolbarCustomization()
LabelCustomization getLabelCustomization()
TextBoxCustomization getTextBoxCustomization()
TextBoxCustomization getTextBoxTwoCustomization()
}
ButtonCustomization
The ButtonCustomization class enables the customization of various buttons presented to the cardholder during the challange process.
public class ButtonCustomization {
void setBackgroundColor(UIColor color)
void setCornerRadius(int cornerRadius)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
void setTextColor(String hexColorCode)
void setTextColor(UIColor color)
void setHeight(CGFloat height)
void setPadding(UIEdgeInsets edge)
UIColor getBackgroundColor()
int getCornerRadius()
String getTextFontName()
int getTextFontSize()
UIColor getTextColor()
String getTextColorHex()
CGFloat getHeight()
}
For example, the following code will configure buttons with red backgrounds and white font:
let uiCustom = UiCustomization()
let customButton = ButtonCustomization()
customButton.setTextColor(color: UIColor.white)
customButton.setBackgroundColor(color:UIColor.red)
try uiCustom.setButtonCustomization(buttonCustomization: customButton, buttonType: .CANCEL)
try uiCustom.setButtonCustomization(buttonCustomization: customButton, buttonType: .CONTINUE)
try uiCustom.setButtonCustomization(buttonCustomization: customButton, buttonType: .NEXT)
try uiCustom.setButtonCustomization(buttonCustomization: customButton, buttonType: .RESEND)
try uiCustom.setButtonCustomization(buttonCustomization: customButton, buttonType: .SUBMIT)
This results in the following Submit button for a Single-Select challenge:
LabelCustomization
The LabelCustomization class enables the customization of various labels displayed throughout the challenge process.
public class LabelCustomization {
void setHeadingTextAlignment(NSTextAlignment textAlignment)
void setHeadingTextColor(UIColor color)
void setHeadingTextFontName(String fontName)
void setHeadingTextFontSize(int fontSize)
void setTextColor(String hexColorCode)
void setTextColor(UIColor color)
void setTextColor(LabelType labelType, UIColor color)
void setTextFontName(String fontName)
void setTextFontName(LabelType labelType, String fontName)
void setTextFontSize(int fontSize)
void setTextFontSize(LabelType, labelType, int fontSize)
void setBackgroundColor(LabelType labelType, UIColor color)
void setPadding(LabelType LabelType, UIEdgeInsets edge)
NSTextAlignment getHeadingTextAlignment()
UIColor getHeadingTextColor()
String getHeadingTextFontName()
int getHeadingTextFontSize()
UIColor getTextColor()
String getTextColorHex()
String getTextFontName()
int getTextFontSize()
}
TextBoxCustomization
The TextBoxCustomization class enables the customization of textboxes displayed throughout the challenge process.
public class TextBoxCustomization {
void setBorderColor(UIColor color)
void setBorderWidth(int borderWidth)
void setCornerRadius(int cornerRadius)
void setTextColor(String hexColorCode)
void setTextColor(UIColor color)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
UIColor getBorderColor()
int getBorderWidth()
int getCornerRadius()
UIColor getTextColor()
String getTextColorHex()
String getTextFontName()
int getTextFontSize()
}
ToolbarCustomization
The ToolbarCustomization class enables the customization of the toolbar displayed throughout the challenge process.
public class ToolbarCustomization {
void setBackgroundColor(UIColor color)
void setButtonText(String buttonText)
void setHeaderText(String headerText)
void setTextColor(String hexColorCode)
void setTextColor(UIColor color)
void setTextFontName(String fontName)
void setTextFontSize(int fontSize)
UIColor getBackgroundColor()
String getButtonText()
String getHeaderText()
UIColor getTextColor()
String getTextColorHex()
String getTextFontName()
int getTextFontSize()
}
Icon Customization
Along with the customization of the look-and-feel of the UI via the UiCustomization class detailed above, it may be desirable to also customize the images utilized by the SDK. There are seven images used by iOS for this that can be customized via a Bundle of images with the following names:
- CollapsedLabelIndicator The icon used to indicate a section that can be collapsed.
- ExpandedLabelIndicator The icon used to indicate a section that can be expanded.
- MultiSelection The icon used for a multi selection option.
- MultiSelectionSelected The icon used for selected multi selection option(s).
- SingleSelection The icon used for a single selection option.
- SingleSelectionSelected The icon used for the selected single selection option.
- WarningIndicator: The icon used (as indicated by the ACS) to draw attention to challenge information text being displayed.
- ipworks3ds_ds_DSID: The directory server logo shown when the progress dialog is displayed during communication with the 3DS Server. The DSID is the lowercase directory server ID matching one configured via a DirectoryServerInfo parameter. The logo displayed by the progress dialog will be selected based on the directory server ID used when creating a transaction.
The bundle containing these images can be passed to the ThreeDS2Service constructor like so:
let threeDS2Service = ThreeDS2Service(bundle: Bundle.main)
Dark Mode
The 3DS SDK supports Dark Mode based on settings configured at the system level. Nothing additional needs to be done in the code. Dark Mode images can be configured for each of the above as well.
ClientEventListener
The ClientEventListener class exposes a number of events that are fired at certain points during the SDK's operation. Below is a list of the available events:
DataPacketIn
Fired when receiving a data packet from the server.
class MyClientEventListener: ClientEventListener {
...
func onDataPacketIn(_ dataPacket: Data) {
//...
}
...
}
This event fires when a packet is received. The entire data packet (including all framing and error detection characters) is contained in the dataPacket parameter. This parameter may be inspected for advanced troubleshooting, or to extract additional response properties beyond the scope of this component.
DataPacketOut
Fired when sending a data packet to the server.
class MyClientEventListener: ClientEventListener {
...
func onDataPacketOut(_ dataPacket: Data) {
//...
}
...
}
This event fires right before each data packet is sent. The entire data packet (including all framing and error detection characters) is contained in the dataPacket parameter. This parameter may be inspected for advanced troubleshooting.
Log
Fires once for each log message.
class MyClientEventListener: ClientEventListener {
...
func onLog(_ logLevel: Int32, _ message: String, _ logType: String) {
print("[\(logType)]\(message)")
}
...
}
Logging is handled through the Log event. This will fire any time a message is built or a response is parsed, including error messages.
When the Log event is fired, the message in question is made available via the message event parameter. The other event arguments are logType and logLevel.
The logType parameter indicates the type of the log entry. Possible values are:
- Info
- RequestHeaders
- ResponseHeaders
- RequestBody
- ResponseBody
- ProxyRequest
- ProxyResponse
- FirewallRequest
- FirewallResponse
- CReq
- CRes
- Erro
- EphemeralKey
- DeviceParams
- SW
A logType of SW indicates a Security Warning. When this value is present, the message parameter will contain a code to indicate a more specific cause of the warning. Below is a list of possible warning message values:
SW Message Value | Description |
---|---|
01 | Tampered, installed from Ad-Hoc or XCode |
02 | Tampered; invalid info dictionary |
03 | Tampered; Info.plist was modified after the app was built |
04 | Tampered; Bundle ID mismatch |
05, XX | Jailbroken; suspicious jailbreak files present on the device |
06, XX | Jailbroken; suspicious jailbreak library loaded |
07, XX | Jailbroken; write permissions enabled on system directories |
08 | Jailbroken; app has permission to fork |
09, XX | Jailbroken; app can query jailbreak URL schemes |
10 | Debugging; p_trace flag detected |
11 | Debugging; internal error: cannot find sysctl |
12 | Debugging; internal error: cannot find getpid |
13 | Debugging; invalid PID |
14, XX | Debugging; reverse engineering tool detected on the device |
15, XX | Debugging; suspicious TCP port detected |
The logLevel parameter in the event indicates the log level to which the current message belongs. Possible values are:
- 0 (None) No events are logged.
- 1 (Info - default) Informational events are logged.
- 2 (Verbose) Detailed data is logged.
- 3 (Debug) Debug data is logged.
Info level logs are available by default. The LogLevel configuration setting, specified in the Client Config settings, can be used to instruct the SDK to raise more or less detailed logs.
It is recommended to output all messages raised in this event to a file for record keeping purposes, or for later debugging issues that may have come up.
SSLServerAuthentication
Fired after the server presents its certificate to the client.
class MyClientEventListener: ClientEventListener {
...
func onSSLServerAuthentication(_ certEncoded: Data, _ certSubject: String, _ certIssuer: String, _ status: String, _ accept: UnsafeMutablePointer<Int32>) {
//...
}
...
}
This event is where the client can decide whether to continue with the connection process or not. The accept parameter is a recommendation on whether to continue or close the connection. This is just a suggestion: application software must use its own logic to determine whether to continue or not.
When accept is False, status shows why the verification failed (otherwise, status contains the string "OK"). If it is decided to continue, you can override and accept the certificate by setting the accept parameter to True.
SSLStatus
Shows the progress of the secure connection.
class MyClientEventListener: ClientEventListener {
...
func onSSLStatus(_ message: String) {
//...
}
...
}
The event is fired for informational and logging purposes only. Used to track the progress of the connection.
Security Event Listener
The SecurityEventListener class exposes a way to be notified of security issues that occur both during initialization of the SDK and at runtime. This is done via a single alarm event:
Alarm
Fired when a security issue is detected.
class MySecurityEventListener: SecurityEventListener {
...
func alarm(_ severity: Severity, _ event: SecurityEvent) {
TransactionManager.transactionManager.showToast("Security alarm: [" + severity.description + "] " + event.description)
}
...
}
If a security issue is detected, the Alarm event will be raised. The severity of the error will be indicated by the severity event parameter. Possible values are:
- LOW
- MEDIUM
- HIGH
The event parameter will indicate which issue was encountered. Possible values are:
- ROOT
- TAMPERED
- INSTALLED_FROM_UNTRUSTED_STORE
- HOOK
- EMULATOR
- DEBUGGING
- DEBUG_ENABLED
For more information on the security checks performed by the component, and recommendations on handling detected issues, see the Security Checks section below.
DirectoryServerInfo
DirectoryServerInfo parameters are used to specify certificate details for the various supported directory servers (DS). When creating a Transaction, the DS_ID is used to specify the certificates to be used for that transaction. Each DirectoryServerInfo consists of three pieces of information:
- DS_ID An identifier used internally in the SDK to match the transaction with a particular DS. Also referred to as an RID.
- DS_CERT Encryption certificate provided by the DS. Used to encrypt the DeviceInfo and generate keys to use for Challenge security.
- DS_CA_CERT The root CA certificate used to issue the DS_CERT. This is used to verify the signature on the response from the DS (ARes packet), and can include the intermediate certificate as well.
Preconfigured Certificates
The 3DS SDK comes preconfigured with certificates for the following Directory Servers. To use these certificates, simply pass one of the DS ID values below when creating the Transaction.
Card Scheme | RID | KID | DS CERT | DS CA CERT(S) |
---|---|---|---|---|
Visa | A000000003 | 747da056-476c-4296-a7c4-7e853e235ef0 | CN=3ds2.rsa.encryption.visa.com Expires: 2027-02-26 | CN=Visa Public RSA Root CA CN=Visa eCommerce Root CA - G2 CN=Visa eCommerce Issuing CA - G2 |
MasterCard | A000000004 | 116f90eee124062e2ca9c8efeb54802c34d963a0 | CN=3ds2.directory.mastercard.com Expires: 2026-07-15 | CN=PRD MasterCard Identity Check Root CA |
Amex | A000000025 | CN=sdk.safekey.encryptkey.com Expires: 2025-05-23 | CN=American Express Private Certification Authority | |
Discover | A000000152 | CN=Discover SDK Expires: 2027-03-07 | CN=extendedroot.protectbuy.com | |
JCB | A000000065 | CN=ds2apr.jcb-tds.com Expires: 2051-03-02 | CN=JCB DS Root CA EMV 3-D Secure | |
UnionPay | A000000333 | CN=CFCA@UnionPay International@N9131000005455878X6@1 Expires: 2025-07-08 | CN=CFCA ACS CA |
Client Config
The SDK accepts one or more of the following configuration settings. These are set as SETTING=VALUE pairs, and set as the clientConfig when building the ConfigParameters.
LogLevel
This config specifies the level of logging enabled in the component. Possible values include:
- 0 - None
- 1 - Info
- 2 - Verbose
- 3 - Debug
MaskSensitive
This setting controls whether sensitive data is masked in the Log event. When set to True (default) the card number value will be replaced with the value *************.
Note: DataPacketOut will always contain the raw unmasked value regardless of this setting. This setting only applies to the Log event.
The default value is True.
Security Checks
The SDK performs security checks and collects device information during initialization. Warnings produced during the 3DS SDK initialization process can be retrieved using the getWarnings method, which returns a list of Warning objects. These can be checked by the app to determine whether or not to proceed with the checkout process:
// check warnings
let warnings = try threeDS2Service.getWarnings()
if warnings.count > 0 {
// process warnings
// abort the checkout if necessary
}
The Warning object consists of the following fields:
Name | Type | Description |
---|---|---|
id | String | Warning identifier. |
message | String | Warning message. |
severity | Severity (enum) | Warning severity level (LOW, MEDIUM, HIGH). |
The following warnings are documented in the EMVCo specification:
Security Warning ID | Description | Severity Level |
---|---|---|
SW01 | The device is jailbroken. | HIGH |
SW02 | The integrity of the SDK has been tampered. | HIGH |
SW03 | An emulator is being used to run the app. | HIGH |
SW04 | A debugger is attached to the app. | MEDIUM |
SW05 | The OS or the OS version is not supported. | HIGH |
To be notified of security issues both at initialization and at runtime, it is recommended to use the SecurityEventListener as well.
Security Checks Performed During Initialization
The following security checks are performed during initialization of the SDK:
- Root detection: several ways of detecting if the device is rooted
- SDK tampering detection: including app signer fingerprint validation and hook detection
- Checks to make sure the app was installed from trusted app stores
- Emulator detection
- Detection of an attached debugger
- OS version detection
These initialization checks result in warnings accessible via the getWarnings detailed above. The message will contain a description of the issue encountered.
Security Checks Performed at Runtime
The following security checks are performed at runtime:
- Emulator detection (high severity): during Transaction.doChallenge()
- Debugging detection (medium severity): during Transaction.doChallenge()
- Method Swizzle Hook detection (high severity): during Transaction.getAuthenticationRequestParameters() and Transaction.doChallenge()
- Fishhook detection (high severity): during Transaction.getAuthenticationRequestParameters() and ThreeDS2Service.createTransaction()
- Anti-debug (preventative): during Transaction.getAuthenticationRequestParameters()
These runtime checks result in firing of the Security Event Listener alarm event, and the activity closing for high severity issues. In the development version of the SDK (without _deploy in the file name), these checks are not performed.
Creating a Transaction
Call the createTransaction method to start a transaction. A reference should be kept for this transaction throughout the entire 3-D Secure authentication process. This method takes the directory server ID, which points to a DirectoryServerInfo configuration parameter added during SDK initialization. The second parameter is a protocol version as a string. Supported version strings are 2.1.0 and 2.2.0:
sdkTransaction = try threeDS2Service.createTransaction(DSInfo.TEST_DS_ID, "2.2.0")
Later, when the transaction is complete, it should be closed via the Transaction object's close method.
Displaying Progress
A progress dialog must be displayed to the end user at certain points in the 3-D Secure process. While performing the challenge, the 3DS SDK will automatically display a progress dialog when appropriate.
A progress dialog must also be displayed to the user while the application is communicating with the 3DS Server and waiting for the authentication request results. The dialog used by the 3DS SDK is available to be used by the application if desired, and can be obtained from the Transaction object via the getProgressView method like so:
// The progress dialog is an instance of ProgressView
var sdkProgressDialog: ProgressView?
// Retrieve the progress dialog from the transaction object instance
sdkProgressDialog = try sdkTransaction?.getProgressView()
sdkProgressDialog?.show()
// Later, to hide/dismiss if desired:
sdkProgressDialog?.close()
The 3DS SDK will automatically hide the dialog when starting the challenge process, so there is no need to explicitly dismiss the dialog in the application code.
Authenticating
The authentication process starts with a call to the Transaction object's getAuthenticationRequestParameters method. When this method is called, the 3DS SDK will encrypt the device information it collected during initialization and make it, along with other SDK information required by the 3DS Server, available in the returned AuthenticationRequestParameters object. This AuthenticationRequestParameters object consists of the following fields:
Name | Description |
---|---|
SDKTransactionId | A transaction identifier randomly generated by the SDK. |
DeviceData | Device data collected by the SDK during initialization and encrypted using the DS key. |
SDKEphemeralPublicKey | The public key component of the ephemeral key pair generated by the SDK. |
SDKAppId | A UUID value that uniquely identifies the app on the device. |
SDKReferenceNumber | Assigned to our SDK by EMVCo after certification. |
MessageVersion | From createTransaction, or a default value from the SDK (2.1.0). |
AuthRequest | Packaged authentication request data to be sent to the 3DS Server. |
The AuthRequest property is a packaged form of the other properties. The app would transmit this to the 3DS Server via a communication channel outside the scope of the 3DS SDK itself. On the server side, this AuthRequest data is designed to be passed directly in to the 3DS Server component's ClientAuthRequest property prior to sending the authentication request to the directory server via its SendAuthRequest method.
When the SendAuthRequest method completes, the Server component's ClientAuthResponse property will contain data that can be sent back to the app and passed to the 3DS SDK to use if a challenge is required.
Response Handling
The 3DS Server is responsible for reading the authentication response from the directory server and indicating to the client (in this case, the app) whether or not a challenge is required. In our 3DS Server component, check the TransactionStatus property after the SendAuthRequest method completes. If this is a value of C or D, a challenge is required.
If no challenge is required (frictionless flow), or authentication cannot be performed for some reason, no further action is required from a 3-D Secure standpoint. Proceed to the Completing Authentication section for details on closing the transaction.
If a challenge is required, the 3DS Server should return the ClientAuthResponse property value to the app for use when starting the challenge process. The Performing a Challenge section below details how to perform the challenge.
Performing a Challenge
If a challenge is required, the challenge is performed by creating the ChallengeParameters (using the ClientAuthResponse from the 3DS Server component) and calling the doChallenge method. The SDK will take care of all communication with the ACS while performing the challenge, as well as prompting the user as needed for the required input. When the challenge process is complete, the relevant ChallengeStatusReceiver callback method will fire.
Challenge Status Receiver
ChallengeStatusReceiver is an interface that should be implemented in the application and passed to the doChallenge when Starting the Challenge. Depending on the result of the challenge process, one of the following methods will be called:
Name | Description |
---|---|
completed | Called when the challenge process (that is, the transaction) is completed. When a transaction is completed, a transaction status shall be available. |
cancelled | Called when the cardholder selects the option to cancel the transaction on the challenge screen. |
timedout | Called when the challenge process reaches or exceeds the timeout interval that is specified during the doChallenge call. |
protocolError | Called when the 3DS SDK receives an EMV 3DS protocol-defined error message from the ACS. |
runtimeError | Called when the 3DS SDK encounters errors during the challenge process. These errors include all errors except those covered by the protocolError method. |
Example implementations of these methods can be found below:
func completed(_ completionEvent: CompletionEvent) {
showToast("Challenge completed with transactionStatus " + completionEvent.getTransactionStatus())
try? closeTransaction()
}
func cancelled() {
showToast("Challenge cancelled.")
try? closeTransaction()
}
func timedout() {
showToast("Challenge timed out.")
try? closeTransaction()
}
func protocolError(_ protocolErrorEvent: ProtocolErrorEvent) {
showToast("Challenge protocolError: " +
protocolErrorEvent.getErrorMessage().getErrorDescription() + "\t" +
protocolErrorEvent.getErrorMessage().getErrorDetails());
try? closeTransaction()
}
func runtimeError(_ runtimeErrorEvent: RuntimeErrorEvent) {
showToast("Challenge runtimeError: " + runtimeErrorEvent.getErrorMessage());
try? closeTransaction()
}
// Helper method
func closeTransaction() throws {
if sdkTransaction != nil {
try sdkTransaction?.close()
sdkTransaction = nil
}
}
Challenge Parameters
ChallengeParameters hold parameters that are required to conduct the challenge process. This is passed to the doChallenge method when starting the challenge process. Available properties, accessible via getters and setters, are:
Name | Type | Description |
---|---|---|
3DSServerTransactionID | String | 3DS Server Transaction ID. |
AcsTransactionID | String | ACS Transaction ID. |
AcsRefNumber | String | ACS Reference Number. |
AcsSignedContent | String | ACS signed content. This data includes the ACS URL, ACS ephemeral public key, and SDK ephemeral public key. |
ThreeDSRequestorAppURL | String | 3DS Requestor App URL. |
ThreeDSServerAuthResponse | String | The Authentication Response from the 3DS Server component. |
These properties can be set individually based on what comes back from the 3DS Server. If using the 3DS Server component, the ThreeDSServerAuthResponse can be set to the generated ClientAuthResponse value, and the other properties will be set automatically based on this value.
let challengeParameters = ChallengeParameters(threeDSServerAuthResponse: authResponse)
Starting the Challenge
If the response from the 3DS Server indicates that a challenge is required, the challenge process is initiated using the doChallenge method. When this is called, control of the UI is handed over to the 3DS SDK. The challenge will be performed by the SDK, and when finished the appropriate ChallengeStatusReceiver event will fire (completed, cancelled, etc.)
try sdkTransaction?.doChallenge(rootViewController: navigationController, challengeParameters: challengeParameters, challengeStatusReceiver: self, timeout: 5)
Name | Type | Description |
---|---|---|
navigationController | UINavigationController | The view controller used by the SDK for the challenge process. |
challengeParameters | ChallengeParameters | ACS details required by the 3DS SDK to conduct the challenge process during the transaction. For details, see the Challenge Parameters section. |
challengeStatusReceiver | ChallengeStatusReceiver | Callback object for notifying the 3DS Requestor App about the challenge status. For details, see the Challenge Status Receiver section. |
timeout | Integer | Timeout interval (in minutes) within which the challenge process must be completed. The minimum timeout interval is 5 minutes. |
Completing Authentication
If the completed callback fires, the CompletionEvent parameter will contain more details on the authentication results. This has two properties: sdkTransactionID, and transactionStatus. The transactionStatus contains the transStatus from the last CRes packet, which would be one of the values below:
- Y: Order completed successfully / Authentication successful
- A: Order completed successfully / Attempts processing performed
- N: Order denied / Not authenticated (denied)
- R: Order denied / Authentication rejected
- U: Order failed due to technical reasons / Authentication could not be performed
Cleanup
The cleanup method frees up resources that are used by the 3DS SDK. It is called only once during a single 3DS Requestor App session:
threeDS2Service.cleanup();
Notes on Application Permissions
The SDK itself does not require any specific permissions outside of internet access, and it will use only the permissions that the application has requested. The app should require permission before the SDK is initialized. This is required by the specification and some device parameters will not be available if permission is not granted.
For a full list of required permissions for each device parameter, see the EMV® 3-D Secure SDK Device Information document, which can be obtained from EMVCo directly.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.