iOS 3DS SDK

Introduction

This document serves as a guide for the integrator of Ravelin’s iOS 3DS SDK, providing details on how the SDK should be configured and integrated into an iOS application or library.

System Requirements and Delivery

Ravelin’s 3DS iOS SDK supports a minimum iOS Version of iOS 10 and the development language used is Swift. We support Swift versions 4.2 and 5. You can also use it with Objective-C code, provided that proper bridging is implemented on your project.

As part of the 3DS SDK product, we include:

  • 3DS SDK and demo apps
  • License key
  • Integration Guide

Versioning

The iOS SDK follows semantic versioning - The version can be described as PROTOCOL.MAJOR.MINOR.PATCH, where:

  • PROTOCOL - major protocol version, i.e. 2
  • MAJOR - new features
  • MINOR - improvements
  • PATCH - bug / security fix

Side Note: Due to limitations by Apple, the minor and patch numbers are concatenated together. When ThreeDS2ServiceSDK.getSDKVersion() is called, the format would then be PROTOCOL.MAJOR.MINORPATCH, for example, for version 2.3.4.5, you’ll get 2.3.45.

Supporting documentation

The following documents should be used in conjunction with this guide:


Integration

This section provides technical details on how to integrate the 3DS SDK into your iOS Project.

Note that the SDK utilises UIKit but it is possible to integrate this into an app using SwiftUI.

Integration options include:

  • Swift Package Manager (SPM)
  • Cocoapods
  • Manual

To assist with integration, a bundle of demo apps is supplied, this consists of:

  • a convenience wrapper intended to illustrate an approach to interfacing with the 3DS2 SDK
  • three simple demo apps, utilising the wrapper, based on:
    1. UIKit and Cocoapods for SDK integration
    2. UIKit and SPM for SDK integration
    3. SwiftUI and SPM for SDK integration

Swift Package Manager Setup

  1. Add the provided credentials to the ~/.netrc file. If such a file doesn’t exist, it should be created.
machine merchant-plug-in.extranet.netcetera.biz
login <myUsername>
password <myPassword>
  1. Add the 3DS2 SDK via SPM/Xcode, an SPM package manifest is available at: git@github.com:unravelin/R3DS2Framework.git

Cocoapods Setup

  1. Install Cocoapods following the official instructions.

  2. In your Podfile, add the 3DS SDK repository as source and dependency. Cocoapods will automatically strip the unsupported architectures when archiving the app.

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/ios-3ds-sdk/Specs.git'

target 'test-project' do
  # Comment the next line if you're not using Swift
  use_frameworks!

  pod 'ThreeDS_SDK'
end
  1. Add the provided credentials to the ~/.netrc file. If such a file doesn’t exist, it should be created.
machine merchant-plug-in.extranet.netcetera.biz
login <myUsername>
password <myPassword>
  1. Install the pods using pod install.

Manual Setup

  1. Extract the iOS SDK .zip archive (as supplied). Inside, there will be a framework file, ThreeDS_SDK.framework

  2. In your project, add the framework in the “Frameworks, Libraries and Embedded Content” section (in the General targets tab).

  3. Create a new “Run Script Phase” in your projects’ target “Build Phases” and paste the following:

bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/ThreeDS_SDK.framework/strip-frameworks.sh"

This step is required when archiving universal binaries, otherwise you might get ERROR ITMS-900087: “Unsupported Architecture. when uploading to the App Store.

License Setup

A license key is distributed along with the SDK. You need to add this in ConfigParameters which are passed upon initialisation of the ThreeDS2Service.

See the demo apps (AppDelegate) for an example utilising the wrapper.

Using the Configuration Builder

Use the ConfigurationBuilder’s licence(key: string) function. After setting all values in the builder, call .configParameters() to generate the ConfigParameters object that can be passed in the initialize method of the ThreeDS2Service class.

let configurationBuilder = ConfigurationBuilder()
try configurationBuilder.license(key: "your_key")
let configParameters = configurationBuilder.configParameters()

Dependencies

The 3DS SDK uses several external dependencies. These libraries are integrated directly into the SDK.

Here you can find a list of these dependencies:

Name Usage Website License Version
ASN1 Decoder Used to parse ASN1 keys and certificates https://github.com/filom/ASN1Decoder MIT 1.2
SwCrypt Used for JWS validation and signing on iOS 10 https://github.com/soyersoyer/SwCrypt MIT 5.1.3
GMEllipticCurveCrypto Used for security around Elliptic Curve Keys https://github.com/ricmoo/GMEllipticCurveCrypto BSD 2 - Clause “Simplified” License 1.1

Transport Security

The EMVCo 3DS Specification requires the communication between the 3DS SDK and the ACS to be done through HTTPS, but there’s no such requirement when downloading the Payment System and Issuer logo images that the SDK displays in the challenge screens. These URLs are provided as parameters by the ACS in the CRes and it’s expected that they will be HTTPS URLs.

If, however, an insecure HTTP URL is provided, the images will not be downloaded due to Apple’s default policies on insecure network connections. For more information on this, please visit the relevant Apple documentation.


SDK Configuration

This section describes the configuration options available on the iOS 3DS SDK, and how to configure it.

Directory Server Configuration

When a transaction is initiated, the SDK will try to obtain information about the Directory Server that will participate in the message flow. This is so that the correct DS Public Key can be used for data encryption, and the correct DS logo is shown.

Scheme and Directory Server information is configured through the ConfigurationBuilder. The following parameters are available for configuration:

  1. Schemes: Which schemes can be used.
  2. DS IDs: Directory Server IDs that belong to a certain scheme.
  3. Scheme’s Public Key: Public keys for each scheme that will be used to encrypt device data.
  4. Scheme’s Root Public Key: Public keys for each scheme that will be used for ACS Certificate Chain verification.
  5. Scheme Logo Name: Logo image name for the scheme.

Using ConfigurationBuilder

The ConfigurationBuilder is an all-in-one API provided by the SDK to allow easier configuration. This class takes Scheme objects, which is the object that holds all values required for proper Scheme Configuration.

See the demo apps for an approach utilising the wrapper.

Example:

let configurationBuilder = ConfigurationBuilder()

let scheme = Scheme(name: "scheme_name")
scheme.ids = ["V000000005","V000000006"]
scheme.logoImageName = "scheme_logo"

// Encryption key configuration with certificate filename.
scheme.encryptionKeyValue = "scheme_encryption.cer"

// Encryption key configuration with PEM string of key.
scheme.encryptionKeyValue = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2APFhfYu2cBvPYpLFiDL8uSzalvoCxHi/1uWDg6k40mRzLq3e9TxiqQ9dhFTfxSOmyztE/k+zb5k9ux4iLaU9nrO1qwqAyP79xmUIDgGEeVOy3JFjkRc3SzU4fMpWKhxkOEBPJ/iwKQYSBvQDz0X7ndbovxo222oHvcMIxy2leFdEQ9cp0A3oT6ozjz1YD6hASI6K4sqSN76M6lcW0dM+ZiE2rTFIB/4tdgTSbjHElDh9VsE9m0JOVvBKp+sI07atca0Mx2aBicjTLKp8BLET2LpNCTNrOL+oRL3H+j1/V7HCD33RVjPWZ5/GWKPuCj5VNpPo/jduD9m3Z8jMsmhwIDAQAB"

// Encryption key configuration with PEM string of certificate.
scheme.encryptionKeyValue = "MIIFWjCCA0ICCQCo3RgSPCQlaTANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJDSDELMAkGA1UECAwCQ0gxCzAJBgNVBAcMAkNIMQwwCgYDVQQKDANOQ0ExDDAKBgNVBAsMA05DQTERMA8GA1UEAwwIaG9zdEBOQ0ExFzAVBgkqhkiG9w0BCQEWCHVzZXJAbmNhMB4XDTIwMDYxMjEzNTI1M1oXDTIxMDYxMjEzNTI1M1owbzELMAkGA1UEBhMCQ0gxCzAJBgNVBAgMAkNIMQswCQYDVQQHDAJDSDEMMAoGA1UECgwDTkNBMQwwCgYDVQQLDANOQ0ExETAPBgNVBAMMCGhvc3RATkNBMRcwFQYJKoZIhvcNAQkBFgh1c2VyQG5jYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJh6hca6jQTSLuD0vKGC1H1YtxoENxPI08DxW+ip4wIy/xbGaC/BWLualVXlqxzNQ7AWPZqnL2enFqg/FPoa4yxZRiJDv6nM/uv/wkxbeV24eGFL/XFyDUgwL+bNEkx02TMyPJGTsy9MSs9Ho8Og8dKTCn8469JPfVkm5nEA2B1DK9ijgtsF8WwkuY8KLt13GATqou46n9kVBUGWGcUcj3LdCeh3JjmNwk3eUcWL4Qkm7nzmPmu9JbAFAUuMj00IZFMPJWzMi+r3EG6RXOGprwbxXEYacACp1gbqWxzaa6azlP1THE9GenJg1Hzc5NjE5UW8ciodnD185PKhVV4tICtSuMxLWv0fB/Lk8RonD2w/fyqnmGY3HaFjgc2zwacIk0WYl4EKxmKyCnSLqQPXLzslxbnnM56HFS9f70O2ZF441QWD8O5n17w2fSTwbGuUM0zkNvhcWZ54oZB6iPnFeU9IvuUGZnucFYjDsHu8YOuFPXNjStDCjNDaXfeQ7t9KfCfQdFRawXKDoAzkTDFxDKH/wPcwsc6MrnC/IaqRQxKqg/rxbyHynZdrwo1gAY+UEl4KjiUah2lR49kFA+ArzNCL+89sdlYQyYLjQAnAC0u5k1L8eKp7QuAgjvT9QGFajCdOGkTaZGGq6+vC9USyTLK1vduLeDW7Z8kMbxAMJg6jAgMBAAEwDQYJKoZIhvcNAQELBQADggIBADK8gNZ3K5uV1UlYMraisebXDlgkbUqIL3H/einNphhPj6qkNkhGvG3o0h/0FhpLH7gXOp58n5XyNvVHb/cEtxdzpMSeoSi5+wQFmsss4Hz0TAeSGH8r+hDJ8ZmbFGOb9T+NETBSRGPOtGusEmjKg2s5yr7PPqLVw8vsJmfvgxfl2wPjFvVOaU0poJjrbcyAaIDW+TCIxllMlt1LkbTfh2xqFK6Be06VYhGRq9e1HzHi5kJnODlm5bEzDtx8Krb6LeWWS+6RKDy+7Us7JEyTR/+K3GeDbdH8OK8g9dv0byRpU5D+sBqwCwm+pDABbuQuAfDIoAk5h4DUMxMJVcKL8iIduoG33ql/kbLaEpzw/DqI0esVbu1RNQA0563Rw40R+oitQmUT0SLWskORZDyJ/u2f/ziPJ7Gy0ycx/6p6aWLHuLsCGKv2hHG1QoXmSZv+JPcKuGjipnGETjww8NIVbD9p641ojeR5z3TTOpl+sMF8cg/WFNURZ/Pv46t9hg9rPTNtSzEyvqaxkYUZKM8q9CVjnGFiIY+y5jPm6IA32XdCavCIIl5/5H8BFxDo3k7QXMHHdMVgJR0c1LGAME5ESG6Bcyaype2DRjfFyx/F7tDqqk0ENZU6fJ2Bfpn9G0CvCrOMdAaRXTdaNwedRnUzGGAczR+epLYyAfk5hw99vpkK"

// Root Certificate configuration with certificate filename.
scheme.rootCertificateValue = "root_certificate.cer"

// Root certificate configuration with PEM string of certificate.
scheme.rootCertificateValue = "MIIDUjCCAjoCCQCJdBdaEqB1GzANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJDSDELMAkGA1UECAwCQ0gxCzAJBgNVBAcMAkNIMQwwCgYDVQQKDANOQ0ExDDAKBgNVBAsMA05DQTENMAsGA1UEAwwESG9zdDEXMBUGCSqGSIb3DQEJARYIdXNlckBuY2EwHhcNMjAwNjEyMTM1NDI2WhcNMjEwNjEyMTM1NDI2WjBrMQswCQYDVQQGEwJDSDELMAkGA1UECAwCQ0gxCzAJBgNVBAcMAkNIMQwwCgYDVQQKDANOQ0ExDDAKBgNVBAsMA05DQTENMAsGA1UEAwwESG9zdDEXMBUGCSqGSIb3DQEJARYIdXNlckBuY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo8nsyE84M23iacFpUC6SyVbyG+9hQWco7yILf2pSPnnEGS8Ng6zL57GVs87Q/kMRCQvndM0ROTZIMb2OQdcita0B8c2eMonDbEqji1ny448gH8P2f1JsgZlaFqZFa1SDqgwiIOyN9IZocdNPYQtavss5Zj73+7EeKiS0nrssCyULz2diH/kju9NUsJelb3ILz3sDXG+lDm0ISk84PYn+pWWp68nFu/2Nk52kGf304WvJGncMLxVHkJ/o/P2oy7G0YD8g1GZbNwZspXS+iUlGOxcXqW4d4w5UgbMiijXmz3eJHOsIza2yACON8nLsoMh1jr2v76TAaXkjqKr0QQ6FTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHuu3Mxki8dQjBg/EI2Vkq+sdnzCclQiGdPh4uBOa+EGmh4e33uGQ5rOHT2DSFHPGQjmNth5r1B/VgJKVRNPdk9nN5+mZv4zpm18G2fGSywTFNvwJVZzavF/sluVtVgmtr+nvLgQAnOl08vlNPd3LecQ1ks/wxh6hV+bSyl6Z4rxDltcp62TgcQHoOURhHlVjrVIdTwqysW5VEPc80LbMrb/zLBVulHlV2Md6UkaPYDfo53G14Vrs2Qu7A3GQP88TGuk6QOynrmnsYEeF/lWSVfTZ50U2ubvpxJvd+ny46orFvdP11p+oDXiO3SrvRyE9Gq+Dz2RQfeK5iATrSK1xOo="

try configurationBuilder.add(scheme)

let configParameters = configurationBuilder.configParameters()

It is also possible to override pre-configured values. To load a Scheme object, call the static functions from the Scheme class with the relevant scheme name.

let configurationBuilder = ConfigurationBuilder()

let scheme = Scheme.diners()
scheme.logoImageName = "diners_scheme_logo"

try configurationBuilder.add(scheme)

let configParameters = configurationBuilder.configParameters()

If the SDK is configured with both a property list file and ConfigurationBuilder, the latter will take priority. If part of the parameters for a scheme, or the same parameters are configured in both places, the values from ConfigurationBuilder will take priority.

Note: If both configurations are used for a given scheme, make sure the same name is used in both places.

Pre-Configured Directory Servers

The iOS SDK comes bundled with configuration for the following Directory Servers:

SDK Configured Scheme RIDs DS Public Key DS Root Public Key DS Logo
Mastercard A000000004 3ds2.directory.mastercard.com - Expiry: 19.11.2021 PRD MasterCard Identity Check Root CA - Expiry: 15.07.2030 mastercard.png
Visa A000000003 3ds2.rsa.encryption.visa.com - Expiry: 22.06.2022 Visa eCommerce Root - Expiry: 24.07.2022 visa.png
Amex A000000025 sdk.safekey.encryptkey.com - Expiry: 03.12.2021 American Express Private Certification Authority - Expiry: 11.08.2029 amex.png
Diners A000000152 Discover SDK Key ProtectBuy Root - Expiry: 03.02.2027 diners.png
JCB A000000065 ds2apr.jcb-tds.com - Expiry: 14.01.2028 JCB DS Root CA EMV 3-D Secure - Expiry: 09.01.2036 jcb.png
Union A000000333 银联国际有限公司 - Expiry: 02.08.2022 CFCA ACS CA - Expiry: 28.09.2035 union.png

The binding between the configuration and the above values is done through the Directory Server RID, and custom configuration has precedence over these pre-configured values.

The pre-configured DS Public Key and DS Root Public Key serve for convenience. You have to verify their compatibility with the Directory Server. The integrators are encouraged to complete the configuration.

Directory Server RID Values

The iOS 3DS SDK has a utility API, DsRidValues, that contains the Directory Server RIDs for the Pre-configured schemes.

Example:

let mastercardDsId = DsRidValues.mastercard // Mastercard DS RID
let visaDsId = DsRidValues.visa // Visa DS RID
let amexDsId = DsRidValues.amex // Amex DS RID
let dinersDsId = DsRidValues.diners // Diners DS RID
let unionDsId = DsRidValues.union // Union DS RID

Restricted Device Info Parameters Configuration

Device Info parameters can be set as restricted, which will in turn make the SDK not collect them.

This is achievable through two main ways: Through ConfigParameters, or ConfigurationBuilder. A list of device info parameters and their corresponding IDs can be found in the official 3DS SDK Device Info documentation.

InvalidInput is thrown if a passed ID doesn’t correspond to any predefined device info parameter.

Using ConfigParameters

By using ConfigParameters.addParam(...), with the following arguments:

group: nil
paramName: "restricted-device-info-parameters"
paramValue: Comma-separated list of device info parameter IDs.

Example:

let configParameters = ConfigParameters()

do {
    try configParameters.addParam(group: nil,
                                  paramName: "restricted-device-info-parameters",
                                  paramValue:"C001,C002,C003,I001,I002")
} catch let error as NSError {
    errorHandler(error.localizedDescription)
}

Using ConfigurationBuilder

The ConfigurationBuilder can be used to configure the restricted parameters. A list of restricted parameters should be passed to restrictedParameters([String]).

When all values are set in the ConfigurationBuilder, the configParameters() function will generate a ConfigParameters object that can be used when calling initialize.

Example:

let configurationBuilder = ConfigurationBuilder()

let restrictedParametersList = ["I001", "I003"]
try configurationBuilder.restrictedParameters(restrictedParametersList)

let configParameters = configurationBuilder.configParameters()

UI Customisation

The iOS 3DS SDK supports customization of UI elements that are being shown by itself. For configuration, the UiCustomization object is used.

For more detailed information, refer to Section 4.5 in the 3DS SDK Specification.

Integrators supporting iOS 13 and above can take advantage of Dark Mode support. If no UI Customisation colours are provided, then Dark Mode is supported by default. If different UI Customisations are specified, remember to provide dark-mode alternatives for the colours.

The iOS 3DS SDK has an extended API for dark-mode colours to be configured. Every method for setting a colour in the classes for UI Customisation has an additional dark-mode colour setter.

Note: If only a light colour is set, the same will be used in dark-mode.

Example:

let buttonCustomization = ButtonCustomization()

try buttonCustomization.setBackgroundColor(hexColorCode: "#000000") // Setting light mode background color.
try buttonCustomization.setDarkBackgroundColor(hexColorCode: "#FFFFFF") // Setting dark mode background color.

Logging Configuration

There are 4 log levels defined in the SDK: debug, info, error (default log level) and noLog

You can change the log level using the ConfigurationBuilder:

let configBuilder = ConfigurationBuilder()

try configBuilder.log(to: LogLevel.noLog) // No SDK logs will be shown
try configBuilder.log(to: LogLevel.error) // Only error SDK logs will be shown
try configBuilder.log(to: LogLevel.info) // Both info and error SDK logs will be shown
try configBuilder.log(to: LogLevel.debug) // All SDK logs will be shown

Permissions

This section describes which iOS Permissions should be granted.

Permission Mandatory Description
Location No Used during the device info collection process for better risk calculation. Request permission from the user before calling initialize.

SDK API

The SDK API complies with the API defined by the EMVCo 3DS SDK Specification. This section describes how the SDK can be used to perform 3DS Authentication of payment / non-payment transactions.

ObjC Class Prefixes

To avoid conflicts of class / protocol names when using the SDK within an ObjectiveC project, all public classes and protocols of the SDK are prefixed with NCA. Eg: NCAThreeDS2ServiceSDK, NCATransaction, NCAToolbarCustomization.

Instantiation

An instance of ThreeDS2ServiceSDK should be created. When creating this object, two constructors are available: One with a bundle argument, and one without. The default value is Bundle.main. In case you want to specify a separate bundle for resources, you may pass the value using the ThreeDS2ServiceSDK(bundle: Bundle) constructor.

/// The bundle from which the SDK will read resources is Bundle.main
let threeDS2Service: ThreeDS2Service = ThreeDS2ServiceSDK()

/// Pass the bundle from which the SDK will read resources
let threeDS2Service: ThreeDS2Service = ThreeDS2ServiceSDK(bundle: bundle)

UI Customisation

The EMV 3DS 2.0 protocol defines an API for Challenge Flow UI Customisation. This includes text colour, fonts, background colour, etc. A list of all available methods can be found in Section 4.5 of the 3DS SDK Specification.

For every integrator supporting iOS 13 or later, the iOS SDK has additional methods for setting colour alternatives for dark-mode. The default methods set light-mode colour.

Class Method Description
Customization setDarkTextColor(hexColorCode: String) Sets the dark-mode text colour.
ButtonCustomization setDarkBackgroundColor(hexColorCode: String) Sets the dark-mode background colour.
ToolbarCustomization setDarkBackgroundColor(hexColorCode: String) Sets the dark-mode background colour.
LabelCustomization setHeadingDarkTextColor(hexColorCode: String) Sets the dark-mode heading text colour.
TextBoxCustomization setDarkBorderColor(hexColorCode: String) Sets the dark-mode border colour.

Initialisation

To initialise the SDK, your application must call the initialize method at the start of the payment stage of a transaction, passing configuration parameters, UI Configuration parameters and user locale. You will also need to set the license key by calling setLicenseKey on your ConfigParameters object.

do {
    let threeDS2Service: ThreeDS2Service = ThreeDS2ServiceSDK()
    let configParameters = ConfigParameters()
    try configParamethers.setLicenseKey(licenseKey: "ey...")
    try threeDS2Service.initialize(configParameters,
                                   locale: nil,
                                   uiCustomization: nil)
    //...
} catch ThreeDS2Error.InvalidInput(let message, _) {
    //...
} catch ThreeDS2Error.SDKAlreadyInitialized(let message, _) {
    //...

} catch {
    //...

}
Function Argument Description
configParameters Instance of ConfigParameters created during SDK Configuration.
locale String that represents the locale for the application’s user interface.
uiCustomization Instance of UICustomization created during SDK Configuration.

During initialization, security checks are performed and device information collected. These parameters will be part of Authentication and will be provided to the ACS via 3DS Server for risk analysis. For more details, refer to Security Features.

Warnings

After security checks are performed, the SDK provides the outcome as list of Warning objects. To obtain the result of these checks, call ThreeDS2Service.getWarnings().

do {
    let sdkWarnings = try threeDS2Service.getWarnings()
} catch ThreeDS2Error.SDKNotInitialized(let message, _){
    //...
} catch {
    //...
}

Each Warning object has a Severity property with value LOW, MEDIUM or HIGH. It’s up to the integrator to decide what to do with this information. The resulting warnings are also provided as part of Device Info in the Authentication process. For more details, please refer to Security Warnings.

Authentication

The 3DS Authentication flow starts with the Authentication Request that is sent to the 3DS Server, where an AReq is created, forwarded to the relevant DS and further forwarded to the relevant ACS. The ACS then evaluates the data in the AReq and responds with an ARes back to the DS, which comes back to the 3DS Requestor Environment via the 3DS Server.

The SDK generates authentication parameters that should be used to build the Authentication Request. All these parameters should be sent to the 3DS Server. These are made available in the Transaction object.

To obtain an instance of Transaction, ThreeDS2Service.createTransaction(...) function can be called:

do {
  let directoryServerId = //...
  try threeDS2Service.createTransaction(directoryServerId: directoryServerId, messageVersion: "2.1.0")
} catch {
  // ...
}
Function Argument Description
directoryServerID The Directory Server ID that will be used. Make sure configuration for this DS already exists in DS Configuration.
messageVersion 3DS Protocol Version that shall be used. If this value is null, the highest version supported will be used.

After the Transaction object has been created, AuthenticationRequestParameters can be obtained by calling Transaction.getAuthenticationRequestParameters().

try {
  let transactionParameters = try transaction.getAuthenticationRequestParameters()
} catch {
  // ...
}

All available AuthenticationRequestParameters are defined in Chapter 4.12 in the EMVCo 3DS SDK Specification.

While the Authentication Request is ongoing, a Processing Screen supplied by the SDK shall be shown. To get an instance of this screen, use Transaction.getProgressView(...).

One requirement from the 3DS Specification is that this processing screen shall be shown for a minimum of two seconds, regardless of authentication response time or result. This requirement shall be implemented by the 3DS SDK Integrator.

Challenge Flow

If the ACS assesses a transaction as high-risk, it forces the Challenge flow onto it. In case of Challenge, the 3DS Requestor calls Transaction.doChallenge(...) and the SDK takes over the Challenge process.

do {
    try transaction.doChallenge(challengeParameters: challengeParamethers,
                                challengeStatusReceiver: challengeStatusReceiver,
                                timeOut:5,
                                inViewController: viewController)
} catch {
    // ...
}
Function Argument Description
challengeParameters Instance of ChallengeParameters, created with values from the Authentication Response.
challengeStatusReceiver Callback object that implements ChallengeStatusReceiver. This is where the application will be notified about the Challenge Result.
timeOut Timeout interval (in minutes) within which the challenge process must be completed. The minimum value is defined to be 5 minutes.
inViewController The view controller in which the challenge flow will be presented modally. This must not be a presented view controller as they cannot present another view controller. If an incorrect argument is passed, the challenge view will not be shown.

Once a Challenge has been started, any calls to Transaction.doChallenge(...) or Transaction.close() will result in an SDK Runtime Error, however the Challenge flow will not be interrupted. When the Challenge result comes through the ChallengeStatusReceiver, Transaction.doChallenge(...) and Transaction.close() can be called again.

Requestor App URL

Starting with version 2.2.0 of 3DS, the application integrating the 3DS SDK can be called from another authentication application during an Out-of-Band challenge flow to indicate completed OOB authentication. To use this feature, the requestor application should define its app URL and provide it to the SDK.

This is done by calling the ChallengeParameters.setThreeDSRequestorAppURL(threeDSRequestorAppURL: String) method.

challengeParameters.setThreeDSRequestorAppURL(threeDSRequestorAppURL: "merchantScheme://appURL?transID=b2385523-a66c-4907-ac3c-91848e8c0067")

The inclusion of this value in ChallengeParameters is optional. This value will be ignored if provided for an irrelevant version of 3DS (like 2.1.0). The transID query parameter value in the URL must be the same as the current ongoing transaction.

On iOS, the handling of events when an Application is opened from a URL scheme / universal link is done in the main Application delegate. In order for the SDK to catch these events, the main Application delegate needs to call the appropriate methods from ThreeDSSDKAppDelegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    // ...

    func application(_ app: UIApplication,
                     open url: URL,
                     options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return ThreeDSSDKAppDelegate.shared.appOpened(url: url)
    }

    func application(_ application: UIApplication,
                     continue userActivity: NSUserActivity,
                     restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        return ThreeDSSDKAppDelegate.shared.appOpened(userActivity: userActivity)
    }
}

Challenge Flow Results

After invoking Transaction.doChallenge(...), the Challenge Flow starts and the SDK takes control of the UI. It will get control back when any of the callback methods from ChallengeStatusReceiver are invoked:

class AppChallengeStatusReceiver: ChallengeStatusReceiver {

    func completed(completionEvent: CompletionEvent) {
        // Handle successfully or unsuccessful completion of challenge flow
    }

    func cancelled() {
        // Handle challenge canceled by the user
    }

    func timedout() {
        // Handle challenge timeout
    }

    func protocolError(protocolErrorEvent: ProtocolErrorEvent) {
        // Handle protocol error that has been send by the ACS
    }

    func runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {
        // Handle error that has occurred in the SDK at runtime
    }
}

When any of these are invoked, the Challenge is considered as finished. As a result, the SDK dismisses the Challenge screen, closes the transaction, cleans up resources and returns control back to your application.

Cleanup

After the 3DS Authentication is finished, the 3DS Requestor should close the Transaction by calling Transaction.close() in order to clear references and avoid memory leaks. When the authentication is done with the Challenge flow, the SDK handles this.

Similarly, in order to free up resources used by ThreeDS2Service, the ThreeDS2Service.cleanup() function can be used. Once an instance of ThreeDS2Service has freed up its resources, it’s in the same state as a newly created ThreeDS2Service and can be used again, however you’ll need to go through initialisation. After ThreeDS2Service is cleaned up, any Transaction objects will be in an invalid state and shall not be used anymore. You should create a new Transaction object after initialising the service.


SDK Error Handling

This section covers SDK Errors and their meaning.

Exceptions

The 3DS2 SDK specification states: the SDK must throw four type of error type:

Exception Description
Invalid input Occurs due to invalid data provided to the SDK.
SDK Already Initialized Occurs when initialize is called on an already initialised ThreeDS2Service object.
SDK Not Initialized Occurs due to attempted usage of an uninitialised ThreeDS2Service object.
SDK runtime error Internal SDK Error. Will contain information describing the error cause more in depth.

Error Codes

Because the SDK supports both Swift and Objective-C, the errors that are thrown are NSError objects. They all contain an error code and localized description with the error message. The error codes for all the aforementioned errors are:

Error Code
Invalid input 1000
SDK Already Initialized 1001
SDK Not Initialized 1002
SDK runtime error 1003

All errors belong to the same domain. The type of error is defined with the error code.

The SDKRuntime and RuntimeErrorEvent errors contain codes that could be useful for debugging your application, or helpful to our Support Team:

Code Description
Transaction Errors
1010 Called method on closed Transaction object. Check error message for what method was called.
1011 Called Transaction object method that has ongoing Challenge Flow. Check message for what method was called.
Configuration Errors
1030 Failed loading Public Key from DS Configuration. Check error message for the invalid value.
1031 Invalid Drawable Resource ID provided in DS Configuration. Check error message for the invalid value.
1032 No DS Configuration nor default values found for the required DS. Check error message for which DS you’re missing configuration for.
License Validation Errors
1050 3DS SDK License is missing.
1051, 1053, 1054 License is in an invalid format.
1052 License has expired. Check error message for the validity period.
Device Data Errors
1060 The provided DS Encryption Key cannot be used because it is neither RSA nor EC type.
Challenge Errors
2000 ACS Signed Content verification failed.
2001 ACS Signed Content signed with unsupported algorithm.
2002 ACS Signed content has invalid signature.

Note: It is possible for the SDK to throw a public error code concatenated with an internal error code. The codes will be separated by a dash delimiter and the public code is always placed first. Eg: 1300-101 - 1300 is the public code and 101 is the internal one.

The error values of SDKRuntime errors can be retrieved from NSError properties:

  • domain: Error domain
  • code: Error code.
  • localizedDescription: Error message.
  • localizedFailureReason: Internal failure code (SDKRuntime error only).

Security Features

This section goes into detail about the security aspects concerning the SDK and its integration.

The SDK implements a number of security functions that are defined in the EMVCo 3DS SDK Specification and in PCI 3DS SDK Security Standard.

Security Warnings

During Initialisation, the SDK performs a number of required security checks. These checks may result in warnings that are handed over to your Application. It’s up to you to act upon these warnings - The SDK will continue to operate as normal should you decide to, for example, ignore them.

Below is a list of the possible warnings:

Code Severity Description
SW01 HIGH Jailbroken device.
SW02 HIGH The SDK has been tampered with.
SW03 HIGH An emulator is being used to run the Application.
SM04 MEDIUM Debugger is attached.
SW05 HIGH Unsupported OS Version.

Secure Communication

The SDK uses several cryptographic methods to secure the communication and transfer of data.

Device Data collected during initialisation is sent to the 3DS Server, which forwards it to the DS and ACS. In order to secure the transmission, the SDK encrypts that data with the DS Public Key in JWE format. The encrypted data can be retrieved by calling AuthenticationRequestParameters.getDeviceData().

After the DS receives this encrypted data, it decrypts it and sends it to the ACS. Using data transferred in the Authentication, the 3DS SDK and ACS exchange keys using the Diffie-Hellman protocol - This establishes the secure channel that is used during the Challenge Flow.

The Ephemeral Key used for the key exchange is generated by the SDK. It can be retrieved in JWK format by invoking AuthenticationRequestParameters.getSDKEphemeralPublicKey(). This key should be sent in the Authentication Request to the 3DS Server together with the other parameters.

PCI 3-D Secure SDK Compliance

This section describes the PCI requirements that are met by the SDK:

Requirement Description
1.1 Security Checks Conduct several security checks of the Requestor environment and display warnings, including: Jailbreak detection, Emulator detection, 3DS SDK Integrity, Debugger detection
1.2 Installed from Approved Source Ensure the Requestor App is installed from a trusted source (Platform Store)
1.3 Run-Time Integrity Checks to detect when SDK functionality has been modified
1.4 Protection against Reverse Engineering Protection against reverse engineering
1.5 Protection of 3DS SDK Reference Data Data is securely stored within the 3DS SDK
2.1 Collection of Sensitive 3DS SDK Data Elements Only data that is essential for functionality is collected and retained for the necessary duration
2.2 Clearing of Sensitive 3DS SDK Data Elements All sensitive data is removed after it’s not needed anymore, unless permitted
2.3 Use of Third-Party Services Third-Party services are documented and only used when justified
2.4 Protection against Disclosure through Unintended Channels Sensitive data is not disclosed outside of the SDK
2.5 Hardcoded 3DS SDK Data Element Sensitive data is not hardcoded in the SDK
2.6 Run-Time Data Protection Run-time data protection against unauthorized third-party access
2.7 UI Protection The UI is secured, and data from it cannot be accessed outside the SDK
2.8 HTML Rendering All requests are intercepted and are handled inside the SDK
2.9 Prevention of External Code of Script Execution Prevent JS Code execution outside the SDK
3.1 Approved Algorithms and Modes of Operation Only approved cryptographic algorithms and methods are used
3.2 Random Number Generator(s) Approved RNG algorithms or libraries are used
3.3 Random Number Entropy Random numbers meet minimum effective security strength
4.1 Threat and Vulnerability Analysis Threats, attack scenarios and / or attack vectors applicable are known and are documented
4.2 Development of Defensive Strategies Various mechanisms are implemented to protect against attack vectors and / or scenarios are designed and implemented
4.3 Software Security Testing Code is tested during its lifecycle
4.4 Vulnerability Identification and Monitoring The SDK is monitored for vulnerabilities / infrastructure exists to report vulnerabilities
4.5 Updates during Transaction Processing The SDK will not update while processing
5.1 Availability of Stakeholder Guidance Guidance is made available and maintained to all stakeholders
5.2 Disclosure of Updates to Stakeholders Stakeholders are updated and informed about changes made to the SDK
5.3 Frequency of Updates to Stakeholder Guidance Updates are made to the SDK as changes as warrant updates

Feedback

© Ravelin Technology Ltd. All rights reserved