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.
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:
The iOS SDK follows semantic versioning - The version can be described as PROTOCOL.MAJOR.MINOR.PATCH
, where:
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
.
The following documents should be used in conjunction with this guide:
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:
To assist with integration, a bundle of demo apps is supplied, this consists of:
~/.netrc
file. If such a file doesn’t exist, it should be created.machine merchant-plug-in.extranet.netcetera.biz
login <myUsername>
password <myPassword>
Install Cocoapods following the official instructions.
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
~/.netrc
file. If such a file doesn’t exist, it should be created.machine merchant-plug-in.extranet.netcetera.biz
login <myUsername>
password <myPassword>
pod install
.Extract the iOS SDK .zip
archive (as supplied). Inside, there will be a framework file, ThreeDS_SDK.framework
In your project, add the framework in the “Frameworks, Libraries and Embedded Content” section (in the General targets tab).
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.
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.
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()
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 |
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.
This section describes the configuration options available on the iOS 3DS SDK, and how to configure it.
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:
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.
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.
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
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.
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)
}
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()
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.
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
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 . |
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.
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
.
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)
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. |
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.
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.
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.
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.
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)
}
}
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.
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.
This section covers SDK Errors and their meaning.
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. |
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 domaincode
: Error code.localizedDescription
: Error message.localizedFailureReason
: Internal failure code (SDKRuntime
error only).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.
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. |
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.
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 |
Was this page helpful?