Skip to content

Commit 94f5c5d

Browse files
authored
Merge pull request #3 from Mastercard-Gateway/hotfix/1.1.3
Hotfix/1.1.3
2 parents a3b7946 + 9b95856 commit 94f5c5d

File tree

12 files changed

+300
-114
lines changed

12 files changed

+300
-114
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ To configure the sample app, compile and run the app on your device. There are t
7878
![Sample app configuration](./sample-configuration.png)
7979

8080
1. The merchant id should have the prefix 'TEST'
81-
1. The region options include ASIA_PACIFIC, EUROPE, NORTH_AMERICA, or MTF
81+
1. The region options include ASIA_PACIFIC, EUROPE, NORTH_AMERICA, INDIA, CHINA, or MTF
8282
1. To find the Heroku test server URL, consult the **[Gateway Test Merchant Server]** (ex: https://{your-app-name}.herokuapp.com)
8383

8484

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ task clean(type: Delete) {
2222
}
2323

2424
ext {
25-
libraryVersionName = '1.1.2'
25+
libraryVersionName = '1.1.3'
2626
}

gateway-android/src/debug/java/com/mastercard/gateway/android/sdk/BaseLogger.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33

44
import android.util.Log;
55

6-
import java.net.HttpURLConnection;
76
import java.util.List;
87
import java.util.Map;
98
import java.util.Set;
109

10+
import javax.net.ssl.HttpsURLConnection;
11+
1112
class BaseLogger implements Logger {
1213

1314
@Override
14-
public void logRequest(HttpURLConnection c, String data) {
15+
public void logRequest(HttpsURLConnection c, String data) {
1516
String log = "REQUEST: " + c.getRequestMethod() + " " + c.getURL().toString();
1617

1718
if (data != null) {
@@ -35,7 +36,7 @@ public void logRequest(HttpURLConnection c, String data) {
3536
}
3637

3738
@Override
38-
public void logResponse(HttpURLConnection c, String data) {
39+
public void logResponse(HttpsURLConnection c, String data) {
3940
String log = "RESPONSE: ";
4041

4142
// log response headers
@@ -59,6 +60,8 @@ public void logResponse(HttpURLConnection c, String data) {
5960
}
6061
}
6162

63+
log += "\n-- Cipher Suite: " + c.getCipherSuite();
64+
6265
String[] parts = log.split("\n");
6366
for (String part : parts) {
6467
logDebug(part);

gateway-android/src/main/java/com/mastercard/gateway/android/sdk/Gateway.java

Lines changed: 15 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,15 @@
3434
import org.json.JSONObject;
3535

3636
import java.io.BufferedReader;
37-
import java.io.ByteArrayInputStream;
3837
import java.io.IOException;
3938
import java.io.InputStream;
4039
import java.io.InputStreamReader;
4140
import java.io.OutputStream;
4241
import java.net.URL;
43-
import java.security.KeyStore;
44-
import java.security.cert.CertificateException;
45-
import java.security.cert.CertificateFactory;
46-
import java.security.cert.X509Certificate;
4742

4843
import javax.net.ssl.HttpsURLConnection;
4944
import javax.net.ssl.SSLContext;
50-
import javax.net.ssl.TrustManager;
51-
import javax.net.ssl.TrustManagerFactory;
45+
import javax.net.ssl.SSLSocketFactory;
5246

5347
import io.reactivex.Single;
5448

@@ -70,11 +64,12 @@ public class Gateway {
7064
* The available gateway regions
7165
*/
7266
public enum Region {
73-
ASIA_PACIFIC("ap-"),
74-
EUROPE("eu-"),
75-
NORTH_AMERICA("na-"),
67+
ASIA_PACIFIC("ap."),
68+
EUROPE("eu."),
69+
NORTH_AMERICA("na."),
7670
INDIA("in."),
77-
MTF("test-");
71+
CHINA("cn."),
72+
MTF("mtf.");
7873

7974
String prefix;
8075

@@ -100,35 +95,6 @@ enum Method {
10095
static final int REQUEST_GOOGLE_PAY_LOAD_PAYMENT_DATA = 10001;
10196
static final String API_OPERATION = "UPDATE_PAYER_DATA";
10297
static final String USER_AGENT = "Gateway-Android-SDK/" + BuildConfig.VERSION_NAME;
103-
static final String INTERMEDIATE_CA = "-----BEGIN CERTIFICATE-----\n" +
104-
"MIIFAzCCA+ugAwIBAgIEUdNg7jANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\n" +
105-
"VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\n" +
106-
"cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\n" +
107-
"IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\n" +
108-
"dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMTQxMDIyMTcw\n" +
109-
"NTE0WhcNMjQxMDIzMDczMzIyWjCBujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\n" +
110-
"dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\n" +
111-
"dGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\n" +
112-
"aG9yaXplZCB1c2Ugb25seTEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9u\n" +
113-
"IEF1dGhvcml0eSAtIEwxSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +
114-
"ANo/ltBNuS9E59s5XptQ7lylYdpBZ1MJqgCajld/KWvbx+EhJKo60I1HI9Ltchbw\n" +
115-
"kSHSXbe4S6iDj7eRMmjPziWTLLJ9l8j+wbQXugmeA5CTe3xJgyJoipveR8MxmHou\n" +
116-
"fUAL0u8+07KMqo9Iqf8A6ClYBve2k1qUcyYmrVgO5UK41epzeWRoUyW4hM+Ueq4G\n" +
117-
"RQyja03Qxr7qGKQ28JKyuhyIjzpSf/debYMcnfAf5cPW3aV4kj2wbSzqyc+UQRlx\n" +
118-
"RGi6RzwE6V26PvA19xW2nvIuFR4/R8jIOKdzRV1NsDuxjhcpN+rdBQEiu5Q2Ko1b\n" +
119-
"Nf5TGS8IRsEqsxpiHU4r2RsCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIBBjAP\n" +
120-
"BgNVHRMECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0\n" +
121-
"cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2Ny\n" +
122-
"bC5lbnRydXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggr\n" +
123-
"BgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFIKi\n" +
124-
"cHTdvFM/z3vU981/p2DGCky/MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+Q\n" +
125-
"EmarMA0GCSqGSIb3DQEBCwUAA4IBAQA/HBpb/0AiHY81DC2qmSerwBEycNc2KGml\n" +
126-
"jbEnmUK+xJPrSFdDcSPE5U6trkNvknbFGe/KvG9CTBaahqkEOMdl8PUM4ErfovrO\n" +
127-
"GhGonGkvG9/q4jLzzky8RgzAiYDRh2uiz2vUf/31YFJnV6Bt0WRBFG00Yu0GbCTy\n" +
128-
"BrwoAq8DLcIzBfvLqhboZRBD9Wlc44FYmc1r07jHexlVyUDOeVW4c4npXEBmQxJ/\n" +
129-
"B7hlVtWNw6f1sbZlnsCDNn8WRTx0S5OKPPEr9TVwc3vnggSxGJgO1JxvGvz8pzOl\n" +
130-
"u7sY82t6XTKH920l5OJ2hiEeEUbNdg5vT6QhcQqEpy02qUgiUX6C\n" +
131-
"-----END CERTIFICATE-----\n";
13298

13399

134100
Logger logger = new BaseLogger();
@@ -490,48 +456,12 @@ GatewayMap executeGatewayRequest(GatewayRequest request) throws Exception {
490456
throw exception;
491457
}
492458

493-
SSLContext createSslContext() throws Exception {
494-
// create and initialize a KeyStore
495-
KeyStore keyStore = createSslKeyStore();
496-
497-
// create a TrustManager that trusts the INTERMEDIATE_CA in our KeyStore
498-
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
499-
tmf.init(keyStore);
500-
501-
TrustManager[] trustManagers = tmf.getTrustManagers();
502-
503-
SSLContext context = SSLContext.getInstance("TLS");
504-
context.init(null, trustManagers, null);
505-
506-
return context;
507-
}
508-
509-
KeyStore createSslKeyStore() throws Exception {
510-
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
511-
keyStore.load(null, null);
512-
513-
// add our trusted cert to the keystore
514-
keyStore.setCertificateEntry("gateway.mastercard.com", readCertificate(INTERMEDIATE_CA));
515-
516-
return keyStore;
517-
}
518-
519-
X509Certificate readCertificate(String cert) throws CertificateException {
520-
byte[] bytes = cert.getBytes();
521-
InputStream is = new ByteArrayInputStream(bytes);
522-
523-
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
524-
}
525-
526459
HttpsURLConnection createHttpsUrlConnection(GatewayRequest request) throws Exception {
527460
// parse url
528461
URL url = new URL(request.url);
529462

530-
// init ssl context with limiting trust managers
531-
SSLContext context = createSslContext();
532-
533463
HttpsURLConnection c = (HttpsURLConnection) url.openConnection();
534-
c.setSSLSocketFactory(context.getSocketFactory());
464+
c.setSSLSocketFactory(createSocketFactory());
535465
c.setConnectTimeout(CONNECTION_TIMEOUT);
536466
c.setReadTimeout(READ_TIMEOUT);
537467
c.setRequestMethod(request.method.name());
@@ -550,6 +480,14 @@ HttpsURLConnection createHttpsUrlConnection(GatewayRequest request) throws Excep
550480
return c;
551481
}
552482

483+
SSLSocketFactory createSocketFactory() throws Exception {
484+
// custom ssl context to enforce certificate pinning
485+
SSLContext sslContext = new GatewaySSLContextProvider().createSSLContext();
486+
487+
// custom socket factory to enable TLSv1.2 on all supported devices
488+
return new GatewayTLSSocketFactory(sslContext);
489+
}
490+
553491
String createAuthHeader(String sessionId) {
554492
String value = "merchant." + merchantId + ":" + sessionId;
555493
return "Basic " + Base64.encodeToString(value.getBytes(), Base64.NO_WRAP);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.mastercard.gateway.android.sdk;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.InputStream;
5+
import java.security.KeyStore;
6+
import java.security.cert.CertificateException;
7+
import java.security.cert.CertificateFactory;
8+
import java.security.cert.X509Certificate;
9+
10+
import javax.net.ssl.SSLContext;
11+
import javax.net.ssl.TrustManagerFactory;
12+
13+
class GatewaySSLContextProvider {
14+
15+
static final String INTERMEDIATE_CA = "-----BEGIN CERTIFICATE-----\n" +
16+
"MIIFAzCCA+ugAwIBAgIEUdNg7jANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\n" +
17+
"VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\n" +
18+
"cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\n" +
19+
"IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\n" +
20+
"dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMTQxMDIyMTcw\n" +
21+
"NTE0WhcNMjQxMDIzMDczMzIyWjCBujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\n" +
22+
"dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\n" +
23+
"dGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\n" +
24+
"aG9yaXplZCB1c2Ugb25seTEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9u\n" +
25+
"IEF1dGhvcml0eSAtIEwxSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +
26+
"ANo/ltBNuS9E59s5XptQ7lylYdpBZ1MJqgCajld/KWvbx+EhJKo60I1HI9Ltchbw\n" +
27+
"kSHSXbe4S6iDj7eRMmjPziWTLLJ9l8j+wbQXugmeA5CTe3xJgyJoipveR8MxmHou\n" +
28+
"fUAL0u8+07KMqo9Iqf8A6ClYBve2k1qUcyYmrVgO5UK41epzeWRoUyW4hM+Ueq4G\n" +
29+
"RQyja03Qxr7qGKQ28JKyuhyIjzpSf/debYMcnfAf5cPW3aV4kj2wbSzqyc+UQRlx\n" +
30+
"RGi6RzwE6V26PvA19xW2nvIuFR4/R8jIOKdzRV1NsDuxjhcpN+rdBQEiu5Q2Ko1b\n" +
31+
"Nf5TGS8IRsEqsxpiHU4r2RsCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIBBjAP\n" +
32+
"BgNVHRMECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0\n" +
33+
"cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2Ny\n" +
34+
"bC5lbnRydXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggr\n" +
35+
"BgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFIKi\n" +
36+
"cHTdvFM/z3vU981/p2DGCky/MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+Q\n" +
37+
"EmarMA0GCSqGSIb3DQEBCwUAA4IBAQA/HBpb/0AiHY81DC2qmSerwBEycNc2KGml\n" +
38+
"jbEnmUK+xJPrSFdDcSPE5U6trkNvknbFGe/KvG9CTBaahqkEOMdl8PUM4ErfovrO\n" +
39+
"GhGonGkvG9/q4jLzzky8RgzAiYDRh2uiz2vUf/31YFJnV6Bt0WRBFG00Yu0GbCTy\n" +
40+
"BrwoAq8DLcIzBfvLqhboZRBD9Wlc44FYmc1r07jHexlVyUDOeVW4c4npXEBmQxJ/\n" +
41+
"B7hlVtWNw6f1sbZlnsCDNn8WRTx0S5OKPPEr9TVwc3vnggSxGJgO1JxvGvz8pzOl\n" +
42+
"u7sY82t6XTKH920l5OJ2hiEeEUbNdg5vT6QhcQqEpy02qUgiUX6C\n" +
43+
"-----END CERTIFICATE-----\n";
44+
45+
public GatewaySSLContextProvider() {
46+
}
47+
48+
SSLContext createSSLContext() throws Exception {
49+
// create and initialize a KeyStore
50+
KeyStore keyStore = createKeyStore();
51+
52+
// create a TrustManager that trusts the INTERMEDIATE_CA in our KeyStore
53+
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
54+
tmf.init(keyStore);
55+
56+
SSLContext context = SSLContext.getInstance("TLS");
57+
context.init(null, tmf.getTrustManagers(), null);
58+
59+
return context;
60+
}
61+
62+
KeyStore createKeyStore() throws Exception {
63+
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
64+
keyStore.load(null, null);
65+
66+
// add our trusted cert to the keystore
67+
keyStore.setCertificateEntry("gateway.mastercard.com", readCertificate(INTERMEDIATE_CA));
68+
69+
return keyStore;
70+
}
71+
72+
X509Certificate readCertificate(String cert) throws CertificateException {
73+
byte[] bytes = cert.getBytes();
74+
InputStream is = new ByteArrayInputStream(bytes);
75+
76+
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
77+
}
78+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.mastercard.gateway.android.sdk;
2+
3+
import java.io.IOException;
4+
import java.net.InetAddress;
5+
import java.net.Socket;
6+
import java.net.UnknownHostException;
7+
8+
import javax.net.ssl.SSLContext;
9+
import javax.net.ssl.SSLSocket;
10+
import javax.net.ssl.SSLSocketFactory;
11+
12+
/**
13+
* Custom SSL socket factory required to enable TLSv1.2 on KitKat devices and below
14+
*/
15+
class GatewayTLSSocketFactory extends SSLSocketFactory {
16+
17+
private SSLSocketFactory internalSSLSocketFactory;
18+
19+
public GatewayTLSSocketFactory(SSLContext context) {
20+
internalSSLSocketFactory = context.getSocketFactory();
21+
}
22+
23+
@Override
24+
public String[] getDefaultCipherSuites() {
25+
return internalSSLSocketFactory.getDefaultCipherSuites();
26+
}
27+
28+
@Override
29+
public String[] getSupportedCipherSuites() {
30+
return internalSSLSocketFactory.getSupportedCipherSuites();
31+
}
32+
33+
@Override
34+
public Socket createSocket() throws IOException {
35+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
36+
}
37+
38+
@Override
39+
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
40+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
41+
}
42+
43+
@Override
44+
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
45+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
46+
}
47+
48+
@Override
49+
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
50+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
51+
}
52+
53+
@Override
54+
public Socket createSocket(InetAddress host, int port) throws IOException {
55+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
56+
}
57+
58+
@Override
59+
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
60+
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
61+
}
62+
63+
private Socket enableTLSOnSocket(Socket socket) {
64+
if(socket != null && (socket instanceof SSLSocket)) {
65+
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
66+
}
67+
return socket;
68+
}
69+
}

gateway-android/src/main/java/com/mastercard/gateway/android/sdk/Logger.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
package com.mastercard.gateway.android.sdk;
1818

19-
import java.net.HttpURLConnection;
19+
20+
import javax.net.ssl.HttpsURLConnection;
2021

2122
interface Logger {
22-
void logRequest(HttpURLConnection c, String data);
23-
void logResponse(HttpURLConnection c, String data);
23+
void logRequest(HttpsURLConnection c, String data);
24+
void logResponse(HttpsURLConnection c, String data);
2425
void logDebug(String message);
2526
}

gateway-android/src/release/java/com/mastercard/gateway/android/sdk/BaseLogger.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package com.mastercard.gateway.android.sdk;
22

33

4-
import java.net.HttpURLConnection;
4+
import javax.net.ssl.HttpsURLConnection;
55

66

77
class BaseLogger implements Logger {
88

99
@Override
10-
public void logRequest(HttpURLConnection c, String data) {
10+
public void logRequest(HttpsURLConnection c, String data) {
1111
// no-op
1212
}
1313

1414
@Override
15-
public void logResponse(HttpURLConnection c, String data) {
15+
public void logResponse(HttpsURLConnection c, String data) {
1616
// no-op
1717
}
1818

0 commit comments

Comments
 (0)