Skip to content

Commit a8eb6f0

Browse files
authored
Merge pull request #162 from sumadhav/future
Modification: P12 certificate's CN name verification
2 parents 93acb0f + ce74b0c commit a8eb6f0

File tree

8 files changed

+148
-94
lines changed

8 files changed

+148
-94
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ Retry Pattern allows to retry sending a failed request and it will only work wit
252252

253253
## Changes
254254
_______________________________
255+
Version Cybersource-sdk-java 6.2.13 (AUGUST,2022)
256+
_______________________________
257+
1)Modified the CYBS P12 certificate's CN name verification to case insensitive.
258+
_______________________________
259+
260+
_______________________________
255261
Version Cybersource-sdk-java 6.2.12 (JULY,2022)
256262
_______________________________
257263
1) Mitigation of Apache WSS4j Security Vulnerability (CVE-2016-1000343, CVE-2018-1000180).

java/src/main/java/com/cybersource/ws/client/Identity.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ public class Identity {
3939

4040
private long lastModifiedDate;
4141

42-
private static final String SERVER_ALIAS = "CyberSource_SJC_US";
43-
4442
private char[] pswd;
4543

4644
/**
@@ -51,7 +49,7 @@ public class Identity {
5149
* @param x509Certificate
5250
* @throws SignException
5351
*/
54-
public Identity(MerchantConfig merchantConfig,X509Certificate x509Certificate,Logger logger) throws SignException {
52+
public Identity(MerchantConfig merchantConfig, X509Certificate x509Certificate) throws SignException {
5553
this.merchantConfig = merchantConfig;
5654
this.x509Cert=x509Certificate;
5755
if(merchantConfig.isJdkCertEnabled() || merchantConfig.isCacertEnabled()){
@@ -66,13 +64,13 @@ private void setupJdkServerCerts() throws SignException {
6664
if (x509Cert != null) {
6765
String subjectDN = x509Cert.getSubjectDN().getName();
6866
if (subjectDN != null) {
69-
String subjectDNrray[] = subjectDN.split("SERIALNUMBER=");
70-
if (subjectDNrray.length == 1 && subjectDNrray[0].contains("CyberSourceCertAuth")){
71-
name = keyAlias = "CyberSourceCertAuth";
67+
String[] subjectDNArray = subjectDN.split("SERIALNUMBER=");
68+
if (subjectDNArray.length == 1 && subjectDNArray[0].toLowerCase().contains(Utility.CYBS_CERT_AUTH.toLowerCase())){
69+
name = keyAlias = subjectDNArray[0].split("=")[1];
7270
}
73-
else if (subjectDNrray.length == 2 && subjectDNrray[1].contains(SERVER_ALIAS)) {
74-
name = SERVER_ALIAS;
75-
serialNumber = subjectDNrray[1].split(",")[0];
71+
else if (subjectDNArray.length == 2 && subjectDNArray[1].toLowerCase().contains(Utility.SERVER_ALIAS.toLowerCase())) {
72+
name = subjectDNArray[1].split("=")[1];
73+
serialNumber = subjectDNArray[1].split(",")[0];
7674
keyAlias = "serialNumber=" + serialNumber + ",CN=" + name;
7775
}else{
7876
throw new SignException("Exception while obtaining private key from KeyStore with alias, '" + merchantConfig.getKeyAlias() + "'");
@@ -147,13 +145,14 @@ private void setUpServer() throws SignException {
147145
if (serialNumber == null && x509Cert != null) {
148146
String subjectDN = x509Cert.getSubjectDN().getName();
149147
if (subjectDN != null) {
150-
String[] subjectDNrray = subjectDN.split("SERIALNUMBER=");
151-
if (subjectDNrray.length == 1 && subjectDNrray[0].contains("CyberSourceCertAuth")){
152-
name = keyAlias = "CyberSourceCertAuth";
148+
String[] subjectDNArray = subjectDN.split("SERIALNUMBER=");
149+
if (subjectDNArray.length == 1 && subjectDNArray[0].toLowerCase().contains(Utility.CYBS_CERT_AUTH.toLowerCase())){
150+
name = keyAlias = subjectDNArray[0].split("=")[1];
153151
}
154-
else if (subjectDNrray.length == 2 && subjectDNrray[0].contains(SERVER_ALIAS)) {
155-
name = SERVER_ALIAS;
156-
serialNumber = subjectDNrray[1];
152+
else if (subjectDNArray.length == 2 && subjectDNArray[0].toLowerCase().contains(Utility.SERVER_ALIAS.toLowerCase())) {
153+
String subjectDName = subjectDNArray[0].split("=")[1];
154+
name = subjectDName.substring(0, subjectDName.length()-1);
155+
serialNumber = subjectDNArray[1];
157156
keyAlias = "serialNumber=" + serialNumber + ",CN=" + name;
158157
}else{
159158
throw new SignException("Exception while obtaining private key from KeyStore with alias, '" + merchantConfig.getKeyAlias() + "'");

java/src/main/java/com/cybersource/ws/client/MessageHandlerKeyStore.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ public MessageHandlerKeyStore() {
2828
* @throws SignEncryptException
2929
*/
3030
public void addIdentityToKeyStore(Identity id, Logger logger) throws SignEncryptException {
31-
if (id == null)
31+
if (id == null) {
3232
return;
33+
}
3334
X509Certificate certificate = id.getX509Cert();
3435
PrivateKey privateKey = id.getPrivateKey();
3536
try {

java/src/main/java/com/cybersource/ws/client/SecurityUtil.java

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
import java.security.cert.X509Certificate;
2222
import java.util.Collections;
2323
import java.util.Enumeration;
24+
import java.util.Map;
2425
import java.util.concurrent.ConcurrentHashMap;
25-
import java.util.concurrent.TimeUnit;
2626

2727
/**
2828
* Utility class for security related functions like loading p12 key, create signed or encrypted doc,
@@ -32,7 +32,6 @@ public class SecurityUtil {
3232

3333
private static final String KEY_FILE_TYPE = "PKCS12";
3434

35-
private static final String SERVER_ALIAS = "CyberSource_SJC_US";
3635
private static final String FAILED_TO_LOAD_KEY_STORE = "Exception while loading KeyStore";
3736
private static final String FAILED_TO_OBTAIN_PRIVATE_KEY = "Exception while obtaining private key from KeyStore with alias";
3837

@@ -173,7 +172,7 @@ private static void readAndStoreCertificateAndPrivateKey(MerchantConfig merchant
173172
identities.put(identity.getKeyAlias(), identity);
174173
continue;
175174
}
176-
Identity identity = new Identity(merchantConfig, (X509Certificate) merchantKeyStore.getCertificate(merchantKeyAlias),logger);
175+
Identity identity = new Identity(merchantConfig, (X509Certificate) merchantKeyStore.getCertificate(merchantKeyAlias));
177176
localKeyStoreHandler.addIdentityToKeyStore(identity, logger);
178177
identities.put(identity.getName(), identity);
179178
}
@@ -208,7 +207,8 @@ public static Document handleMessageCreation(Document signedDoc, String merchant
208207
WSSecEncrypt encrBuilder = new WSSecEncrypt(secHeader);
209208
//Set the user name to get the encryption certificate.
210209
//The public key of this certificate is used, thus no password necessary. The user name is a keystore alias usually.
211-
encrBuilder.setUserInfo(identities.get(SERVER_ALIAS).getKeyAlias());
210+
String serverAlias = getServerAlias(identities);
211+
encrBuilder.setUserInfo(identities.get(serverAlias).getKeyAlias());
212212

213213
/*This is to reference a public key or certificate when signing or encrypting a SOAP message.
214214
*The following valid values for these configuration items are:
@@ -234,8 +234,8 @@ public static Document handleMessageCreation(Document signedDoc, String merchant
234234
KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_256);
235235
signedEncryptedDoc = encrBuilder.build(localKeyStoreHandler, keyGen.generateKey());
236236
} catch (WSSecurityException e) {
237-
logger.log(Logger.LT_EXCEPTION, "Failed while encrypting signed requeest for , '" + merchantId + "'" + " with " + SERVER_ALIAS);
238-
throw new SignEncryptException("Failed while encrypting signed requeest for , '" + merchantId + "'" + " with " + SERVER_ALIAS, e);
237+
logger.log(Logger.LT_EXCEPTION, "Failed while encrypting signed request for , '" + merchantId + "'" + " with " + serverAlias);
238+
throw new SignEncryptException("Failed while encrypting signed request for , '" + merchantId + "'" + " with " + serverAlias, e);
239239
}
240240
encrBuilder.prependToHeader();
241241
return signedEncryptedDoc;
@@ -343,7 +343,7 @@ public static void readJdkCert(MerchantConfig merchantConfig, Logger logger)
343343
continue;
344344
}
345345
Identity identity = new Identity(merchantConfig,
346-
(X509Certificate) keystore.getCertificate(merchantKeyAlias), logger);
346+
(X509Certificate) keystore.getCertificate(merchantKeyAlias));
347347
localKeyStoreHandler.addIdentityToKeyStore(identity, logger);
348348
identities.put(identity.getName(), identity);
349349
}
@@ -363,8 +363,6 @@ private static void loadJavaKeystore(MerchantConfig merchantConfig, Logger logge
363363
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
364364
keystore.load(is, merchantConfig.getCacertPassword().toCharArray());
365365

366-
Identity identity;
367-
368366
java.security.cert.Certificate[] cert = keystore.getCertificateChain(merchantConfig.getKeyAlias());
369367
if (cert == null) {
370368
throw new SignException("Empty Keystore or Missing Certificate ");
@@ -378,23 +376,23 @@ private static void loadJavaKeystore(MerchantConfig merchantConfig, Logger logge
378376
+ merchantConfig.getKeyAlias() + "'");
379377
throw new SignException(e);
380378
}
381-
382-
for (int i = 0; i < cert.length; i++) {
383-
if (merchantConfig.getKeyAlias().equals(keystore.getCertificateAlias(cert[i]))) {
384-
identity = new Identity(merchantConfig, (X509Certificate) cert[i], key, logger);
379+
Identity identity;
380+
for (java.security.cert.Certificate certificate : cert) {
381+
if (merchantConfig.getKeyAlias().equals(keystore.getCertificateAlias(certificate))) {
382+
identity = new Identity(merchantConfig, (X509Certificate) certificate, key, logger);
385383
localKeyStoreHandler.addIdentityToKeyStore(identity, logger);
386384
identities.put(identity.getKeyAlias(), identity);
387385
} else {
388-
identity = new Identity(merchantConfig, (X509Certificate) cert[i], logger);
386+
identity = new Identity(merchantConfig, (X509Certificate) certificate);
389387
localKeyStoreHandler.addIdentityToKeyStore(identity, logger);
390388
identities.put(identity.getName(), identity);
391389
}
392390
}
393-
java.security.cert.Certificate serverCert = keystore.getCertificate(SERVER_ALIAS);
391+
java.security.cert.Certificate serverCert = keystore.getCertificate(getServerAlias(identities));
394392
if (serverCert == null) {
395393
throw new SignException("Missing Server Certificate ");
396394
}
397-
identity = new Identity(merchantConfig, (X509Certificate) serverCert, logger);
395+
identity = new Identity(merchantConfig, (X509Certificate) serverCert);
398396
localKeyStoreHandler.addIdentityToKeyStore(identity, logger);
399397
identities.put(identity.getName(), identity);
400398

@@ -427,4 +425,23 @@ private static void loadJavaKeystore(MerchantConfig merchantConfig, Logger logge
427425
}
428426

429427
}
428+
429+
protected static String getServerAlias(Map<String, Identity> identitiesMapper) {
430+
String serverAlias = Utility.SERVER_ALIAS;
431+
if(!identitiesMapper.containsKey(serverAlias)) {
432+
if(identitiesMapper.containsKey(serverAlias.toLowerCase())) {
433+
serverAlias = serverAlias.toLowerCase();
434+
} else if(identitiesMapper.containsKey(serverAlias.toUpperCase())) {
435+
serverAlias = serverAlias.toUpperCase();
436+
} else {
437+
for(String identityKey :identitiesMapper.keySet()) {
438+
if(identityKey.equalsIgnoreCase(serverAlias)) {
439+
serverAlias = identityKey;
440+
break;
441+
}
442+
}
443+
}
444+
}
445+
return serverAlias;
446+
}
430447
}

java/src/main/java/com/cybersource/ws/client/Utility.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ private Utility() {
4545
/**
4646
* Version number of this release.
4747
*/
48+
public static final String SERVER_ALIAS = "CyberSource_SJC_US";
49+
public static final String CYBS_CERT_AUTH = "CyberSourceCertAuth";
4850
public static final String VERSION = "6.2.13";
4951
public static final String ORIGIN_TIMESTAMP = "v-c-client-iat";
5052
public static final String SDK_ELAPSED_TIMESTAMP = "v-c-client-computetime";
Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,82 @@
11
package com.cybersource.ws.client;
22

3-
import org.junit.Before;
43
import org.junit.Test;
54
import org.mockito.Mockito;
65

76
import static org.junit.Assert.*;
87

98
import java.io.File;
9+
import java.io.IOException;
1010
import java.io.InputStream;
1111
import java.security.Principal;
1212
import java.security.PrivateKey;
1313
import java.security.cert.X509Certificate;
1414
import java.util.*;
1515

16-
public class IdentityTest{
16+
public class IdentityTest {
1717

18-
private MerchantConfig config;
19-
20-
@Before
21-
public void setUp() throws Exception {
22-
//Loading the properties file from src/test/resources
23-
Properties merchantProperties = new Properties();
24-
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("test_cybs.properties");
25-
if (in == null) {
26-
throw new RuntimeException("Unable to load test_cybs.properties file");
27-
}
28-
merchantProperties.load(in);
29-
config = new MerchantConfig(merchantProperties, merchantProperties.getProperty("merchantID"));
30-
}
18+
@Test
19+
public void testSetUpMerchant() throws SignException, ConfigException{
20+
File p12file = Mockito.mock(File.class);
21+
MerchantConfig mc = Mockito.mock(MerchantConfig.class);
22+
23+
String keyAlias = "CN="+mc.getMerchantID()+",SERIALNUMBER=400000009910179089277";
24+
X509Certificate x509Cert = Mockito.mock(X509Certificate.class);
25+
Principal principal = Mockito.mock(Principal.class);
26+
PrivateKey pkey = Mockito.mock(PrivateKey.class);
27+
Logger logger = Mockito.mock(Logger.class);
28+
Mockito.when(x509Cert.getSubjectDN()).thenReturn(principal);
29+
Mockito.when(principal.getName()).thenReturn(keyAlias);
3130

32-
@Test
33-
public void testSetUpMerchant() throws SignException, ConfigException{
34-
File p12file = Mockito.mock(File.class);
35-
MerchantConfig mc = Mockito.mock(MerchantConfig.class);
36-
37-
String keyAlias = "CN="+mc.getMerchantID()+",SERIALNUMBER=400000009910179089277";
38-
X509Certificate x509Cert = Mockito.mock(X509Certificate.class);
39-
Principal principal = Mockito.mock(Principal.class);
40-
PrivateKey pkey = Mockito.mock(PrivateKey.class);
41-
Logger logger = Mockito.mock(Logger.class);
42-
Mockito.when(x509Cert.getSubjectDN()).thenReturn(principal);
43-
Mockito.when(principal.getName()).thenReturn(keyAlias);
44-
45-
Mockito.when(mc.getKeyFile()).thenReturn(p12file);
31+
Mockito.when(mc.getKeyFile()).thenReturn(p12file);
4632
Mockito.when(mc.getKeyPassword()).thenReturn("testPwd");
47-
Identity identity = new Identity(mc,x509Cert,pkey,logger);
48-
assertEquals(identity.getName(), mc.getMerchantID());
49-
assertEquals(identity.getSerialNumber(), "400000009910179089277");
33+
Identity identity = new Identity(mc,x509Cert,pkey,logger);
34+
assertEquals(identity.getName(), mc.getMerchantID());
35+
assertEquals(identity.getSerialNumber(), "400000009910179089277");
5036
assertEquals(String.valueOf(identity.getPswd()), "testPwd");
51-
assertNotNull(identity.getPrivateKey());
52-
}
53-
54-
@Test
55-
public void testsetUpServer() throws SignException {
56-
String keyAlias;
57-
if(config.isJdkCertEnabled() || config.isCacertEnabled()) {
58-
keyAlias = "SERIALNUMBER=400000009910179089277,CN=CyberSource_SJC_US";
59-
} else {
60-
keyAlias = "CN=CyberSource_SJC_US,SERIALNUMBER=400000009910179089277";
61-
}
37+
assertNotNull(identity.getPrivateKey());
38+
}
6239

63-
X509Certificate x509Cert = Mockito.mock(X509Certificate.class);
64-
Principal principal = Mockito.mock(Principal.class);
65-
Logger logger = Mockito.mock(Logger.class);
66-
Mockito.when(x509Cert.getSubjectDN()).thenReturn(principal);
67-
Mockito.when(principal.getName()).thenReturn(keyAlias);
68-
Identity identity = new Identity(config,x509Cert,logger);
69-
assertEquals(identity.getName(), "CyberSource_SJC_US");
70-
assertEquals(identity.getSerialNumber(), "400000009910179089277");
71-
assertNull(identity.getPrivateKey());
72-
}
40+
@Test
41+
public void testSetUpServerForP12Certs() throws SignException, IOException, ConfigException {
42+
Properties merchantProps = getConfigProps();
43+
merchantProps.setProperty("enableCacert", "false");
44+
MerchantConfig customConfig = new MerchantConfig(merchantProps, merchantProps.getProperty("merchantID"));
45+
String keyAlias = "CN=CyberSource_SJC_US,SERIALNUMBER=400000009910179089277";
46+
X509Certificate x509Cert = Mockito.mock(X509Certificate.class);
47+
Principal principal = Mockito.mock(Principal.class);
48+
Mockito.when(x509Cert.getSubjectDN()).thenReturn(principal);
49+
Mockito.when(principal.getName()).thenReturn(keyAlias);
50+
Identity identity = new Identity(customConfig, x509Cert);
51+
assertEquals(identity.getName(), Utility.SERVER_ALIAS);
52+
assertEquals(identity.getSerialNumber(), "400000009910179089277");
53+
assertNull(identity.getPrivateKey());
54+
}
55+
56+
@Test
57+
public void testSetUpServerForCaCerts() throws SignException, IOException, ConfigException {
58+
Properties merchantProps = getConfigProps();
59+
merchantProps.setProperty("enableCacert", "true");
60+
MerchantConfig customConfig = new MerchantConfig(merchantProps, merchantProps.getProperty("merchantID"));
61+
String keyAlias = "SERIALNUMBER=400000009910179089277,CN=CyberSource_SJC_US";
62+
X509Certificate x509Cert = Mockito.mock(X509Certificate.class);
63+
Principal principal = Mockito.mock(Principal.class);
64+
Mockito.when(x509Cert.getSubjectDN()).thenReturn(principal);
65+
Mockito.when(principal.getName()).thenReturn(keyAlias);
66+
Identity identity = new Identity(customConfig, x509Cert);
67+
assertEquals(identity.getName(), Utility.SERVER_ALIAS);
68+
assertEquals(identity.getSerialNumber(), "400000009910179089277");
69+
assertNull(identity.getPrivateKey());
70+
}
71+
72+
private Properties getConfigProps() throws IOException {
73+
Properties merchantProperties = new Properties();
74+
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("test_cybs.properties");
75+
if (in == null) {
76+
throw new RuntimeException("Unable to load test_cybs.properties file");
77+
}
78+
merchantProperties.load(in);
79+
return merchantProperties;
80+
}
7381

74-
}
82+
}

0 commit comments

Comments
 (0)