Certificate pinning
The iOS SDK provides functionality to pin your server's certificate. If you pin the server's certificate itself, you will need to deploy a new version of the application when you change the servers' certificate. The best alternative is to use the intermediate certificate of the Certificate Authority used to get your SSL server's certificate (the second level in the certificate chain). This gives you the option to renew the server certificate without having to deploy a new version of the application.
Optional certificate pinning (SDK 13.3.0 and later)
From SDK version 13.3.0, certificate pinning is dynamically enabled or disabled based on whether certificates are present in the ClientBuilder configuration:
- If the SDK Configurator output contains a certificate (
X509PEMCertificatesinOneginiConfigModel), certificate pinning is enabled. - If no certificate is present in the generated
OneginiConfigModel(that is,X509PEMCertificatesis empty), certificate pinning is disabled.
Warning
Disabling certificate pinning reduces the security of the connection between the app and your server. Certificate pinning is strongly recommended under production apps. Only bypass pinning where OS-level certificate validation is an acceptable alternative for your security policy.
When pinning is disabled, the SDK logs the following warning during initialisation:
[OneWelcomeSDK] WARNING: Certificate pinning is disabled. No X.509 PEM certificates were provided to ClientBuilder. Connections will use standard OS-level certificate validation.
Manual certificate pinning
Export the certificate
You can use Firefox to export the certificate. Click the lock of the SSL website and choose more information. In the security tab, press View certificate. Then go to the details tab and choose which certificate in the chain you wish to export.
Certificate tampering protection
To prevent tampering or detect if certificates are replaced by different ones, the certificates are provided to the client in base64 format. To obtain a base64-encoded certificate, the DER-encoded certificate must be converted to PEM format with the following command:
openssl x509 -in <filename>.cer -inform der -out <filename>.pem -outform pem
The content of the <filename>.pem file is an armored base64 representation of the certificate. The content of the file stripped from its armor:
---Begin---
...
---End---
The rows must be provided to the client before a service request is made. The best practice is to add the base64-encoded certificate to the client during initialization using ClientBuilder.
NSString *const certificate = @"AaXeRCk/luuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cqcdnUl4XmGFO3";
ONGClientBuilder *clientBuilder = [[ONGClientBuilder alloc] init];
self.oneginiClient = [[[clientBuilder setConfigModel:configModel] setX509PEMCertificates:@[certificate]] build];
let certificate = "AaXeRCk/luuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cqcdnUl4XmGFO3"
let oneginiClient = ClientBuilder().setConfigModel(configModel)
.setX509PEMCertificates([certificate])
.build()
Automated certificate pinning
Certificate pinning can be done automatically as a part of the process done by the Mobile SDK Configurator. In this case, calling the setX509PEMCertificates: method is not required. ClientBuilder automatically finds the ConfigModel in order to configure certificates correctly.
ONGClientBuilder *clientBuilder = [[ONGClientBuilder alloc] init];
self.oneginiClient = [clientBuilder build];
ClientBuilder().build()
Calling resources outside the main domain
The certificate pinning mechanism will not allow you to call for a resource domain which is not set as the main domain in the ConfigModel. Since the ConfigModel can be set only for one domain, we introduced an optional method to fetch resources for different domains covered by the certificates set with the ConfigModel.
Call the setAdditionalResourceUrls method before the build() command to fetch resources for additional domains.
ClientBuilder()
.setAdditionalResourceUrls(["https://www.domain1.com", "https://domain2.com"])
.build()
.start { ... }