diff --git a/domain.md b/domain.md
new file mode 100644
index 0000000..c8be5c4
--- /dev/null
+++ b/domain.md
@@ -0,0 +1,207 @@
+# Externalize API Gateway domain certificates
+
+## Admin Node manager
+
+- Create a CSR file
+```bash
+./gen_domain_cert.py --domain-id=dss --out=csr --O=Axway --OU=DSS --C=US --ST=AZ --L=Scottsdale --pass-file=rootcerts/pass.txt
+```
+command creates a folder named dss under apigw-emt-scripts-2.1.0-SNAPSHOT/certs/ with following files
+
+ - dss.csr
+ - dss-key.pem
+
+- Create CA CSR, certificate and key
+```bash
+openssl genrsa -aes256 -out CA.key 2048
+openssl req -new -sha256 -key CA.key -out CA.csr -subj "/C=US/ST=AZ/L=Scottsdale/O=AXWAY/CN=CACERTIFICATE"
+openssl x509 -signkey CA.key -in CA.csr -req -days 3650 -out CA.pem
+```
+command creates following files
+
+ - CA.key
+ - CA.csr
+ - CA.pem
+ - CA.srl
+
+- Create a file openssl.cnf with following content
+
+```text
+[policy_any]
+domainComponent = optional
+organizationalUnitName = optional
+commonName = supplied
+
+[req]
+distinguished_name = req_distinguished_name
+
+[req_distinguished_name]
+
+[x509_extensions]
+
+[domain_extensions]
+basicConstraints = CA:TRUE, pathlen:0
+keyUsage = digitalSignature, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
+
+[admin_node_manager_extensions]
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, dataEncipherment, keyAgreement, keyEncipherment
+extendedKeyUsage = serverAuth, clientAuth, 1.3.6.1.4.1.17998.10.1.1.2.1, 1.3.6.1.4.1.17998.10.1.1.2.2
+subjectAltName = @alt_names
+
+[node_manager_extensions]
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, dataEncipherment, keyAgreement
+extendedKeyUsage = serverAuth, clientAuth, 1.3.6.1.4.1.17998.10.1.1.2.1
+subjectAltName = @alt_names
+
+[gateway_extensions]
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, dataEncipherment, keyAgreement
+extendedKeyUsage = serverAuth, clientAuth, 1.3.6.1.4.1.17998.10.1.1.2.3
+subjectAltName = @alt_names
+
+[alt_names]
+
+DNS.1 = localhost
+IP.1 = 127.0.0.1
+
+```
+
+- Sign dss.csr with CA certificate and key using openssl configuration
+
+```bash
+openssl x509 -req -days 360 -in dss.csr -CA CA.pem -CAkey CA.key -CAcreateserial -out signedbyCA.crt -sha256 -extensions admin_node_manager_extensions -extfile openssl.cnf
+```
+
+- Create a P12 file from CA signed certificate and key file
+
+```bash
+openssl pkcs12 -export -in signedbyCA.crt -inkey dss-key.pem -out domain.p12 -chain -CAfile CA.pem -name 'topology-cert'
+```
+**alias name should be 'topology-cert'**
+
+- Prepare Admin Node Manager fed file
+
+ - Export Admin Node manager fed from classic installation, remove existing topology-cert and change remove / rename port name without blank space (e.g sslport)
+
+ - Import loadable module
+ Policystudio using File -> Import -> Import Custom filters -> select apim-policy-password-cert-env/src/main/resources/typeSet.xml.
+
+ - Export fed file
+
+- Configure environment variable (docker-compose / kubernetes deployment)
+
+```yaml
+ # docker-compose.yaml example
+ environment:
+ EMT_TOPOLOGY_LOG_ENABLED: 'true'
+ EMT_TOPOLOGY_LOG_DEST: 3
+ certandkey_sslport: /opt/Axway/apigateway/domain.p12
+ certandkeypassword_sslport: changeme
+ certandkeymtls_sslport: 'true'
+```
+
+- comment lines related to certificate generation in apigw-emt-scripts-2.1.0-SNAPSHOT/Dockerfiles/emt-nodemanager/scripts/setup_emt_nodemanager.py
+```python
+ try:
+ # self._generateTopologyCert(nmHandler)
+ # self._storeCertsInEntityStore(nmHandler)
+
+ localNodeManager, topology, topologyParams = self._createTopologyJson()
+ # print("Enabling SSL on management interface")
+ # nmHandler.enableSSLInterface(True, TopologyCertificate.CERT_ALIAS, topologyParams)
+ # self._updateConfigFiles(localNodeManager, topology)
+
+ # Delete the cert generation temp directory
+ shutil.rmtree(nmHandler.tempCertPath)
+
+ except Exception, e:
+ _fail("Error generating topology cert: %s" % e)
+```
+- Build Admin Node Manger Image
+
+```bash
+./build_anm_image.py --default-cert --default-user --parent-image=apigw-base --merge-dir=/Users/rnatarajan/APIM/apigw-emt-scripts-2.1.0-SNAPSHOT/apigateway --fed extanm.fed --out-image=admin-node-manager-ext-ca-env:latest
+```
+**param default-cert is not used, but it is a mandatory argument for building anm image**
+
+## Configure Gateway
+
+- Create a CSR file
+
+```bash
+./gen_domain_cert.py --domain-id=dssgateway --out=csr --O=Axway --OU=DSS --C=US --ST=AZ --L=Scottsdale --pass-file=rootcerts/pass.txt
+```
+command creates a folder named dssgateway under apigw-emt-scripts-2.1.0-SNAPSHOT/certs/ with following files
+
+ - dssgateway.csr
+ - dssgateway-key.pem
+- Copy CA.pem, CA.key, CA.srl and openssl files from dss folder to dssgateway folder
+
+```bash
+dssgateway$cp ../dss/CA.pem .
+dssgateway$cp ../dss/CA.key .
+dssgateway$cp ../dss/CA.srl .
+dssgateway$cp ../dss/openssl.cnf .
+```
+- Sign dss.csr with CA certificate and key using openssl configuration
+
+```bash
+openssl x509 -req -days 360 -in dssgateway.csr -CA CA.pem -CAkey CA.key -CAcreateserial -out signedbygatewayCA.crt -sha256 -extensions gateway_extensions -extfile openssl.cnf
+```
+
+command creates a file named signedbygatewayCA.crt
+
+- Create p12 file **without password**
+
+```bash
+openssl pkcs12 -export -in signedbygatewayCA.crt -inkey dssgateway-key.pem -out topology.p12 -chain -CAfile CA.pem -name 'topology-cert' -passout pass:
+```
+
+- Prepare Admin Node Manager fed file
+
+ - Import loadable module
+ Policystudio using File -> Import -> Import Custom filters -> select apim-policy-password-cert-env/src/main/resources/typeSet.xml.
+
+ - Export fed file
+
+- Configure environment variable (docker-compose / kubernetes deployment)
+
+```yaml
+ # docker-compose.yaml example
+ # Mandatory
+ volumes:
+ - /Users/rnatarajan/APIM/apigw-emt-scripts-2.1.0-SNAPSHOT/certs/dssgateway/p12:/opt/Axway/apigateway/groups/certs/
+ environment:
+ EMT_ANM_HOSTS: nodemgr:8090
+ CASS0: host.docker.internal
+ CASS_HOST: host.docker.internal
+ CASS_USER: dba
+ CASS_PASSWORD: super
+ CASS_KEYSPACE: axwayapim
+ # We should use same path
+ gatewaytoplogycertandkey_domain: /opt/Axway/apigateway/groups/certs/topology.p12
+ gatewaytoplogycertandkeypassword_domain: ''
+```
+
+- comment lines related to certificate generation in apigw-emt-scripts-2.1.0-SNAPSHOT/Dockerfiles/emt-gateway/scripts/setup_emt_instance.py
+
+```python
+def _setup():
+ _mergePolAndEnvToFed()
+ _installCustomFedFile()
+ _setupApiManager()
+ _createInstanceDirStructure()
+ _customizeInstallation()
+ _checkLicense()
+
+ # ch = CertHandler()
+ # ch.generateCert()
+ # ch.enableSSLInterface()
+```
+
+- Build API Gateway Image
+```bash
+./build_gw_image.py --default-cert --license=/Users/rnatarajan/APIM/apigw-emt-scripts-2.1.0-SNAPSHOT/licenses/apim.lic --parent-image=apigw-base --merge-dir=/Users/rnatarajan/APIM/apigw-emt-scripts-2.1.0-SNAPSHOT/apigateway --fed=container_env.fed --out-image=apim-cert-ca-env:latest
+```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 53f4357..887a406 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.axway
apim-env-module
- 1.1.3
+ 1.1.4
apim-env-module
https://axway.com
@@ -48,7 +48,6 @@
${apim.lib.path}/vordel-apigateway-7.7.0.20201130-5.jar
-
vordel-core-runtime
vordel-core-runtime
system
@@ -86,12 +85,12 @@
org.apache.logging.log4j
log4j-api
- 2.11.2
+ 2.13.3
org.apache.logging.log4j
log4j-core
- 2.13.2
+ 2.13.3
diff --git a/src/main/java/com/axway/CertHelper.java b/src/main/java/com/axway/CertHelper.java
index d7bba6d..5981218 100644
--- a/src/main/java/com/axway/CertHelper.java
+++ b/src/main/java/com/axway/CertHelper.java
@@ -7,8 +7,7 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.util.Base64;
-import java.util.Enumeration;
+import java.util.*;
public class CertHelper {
@@ -63,18 +62,25 @@ public PKCS12 parseP12(String content, char[] password) throws KeyStoreException
}
- public X509Certificate parseX509(String base64EncodedCert) throws CertificateException, FileNotFoundException {
+ public List parseX509(String base64EncodedCertOrFilePath) throws CertificateException, FileNotFoundException {
- File file = new File(base64EncodedCert);
+ File file = new File(base64EncodedCertOrFilePath);
InputStream inputStream = null;
if(file.exists()){
inputStream = new FileInputStream(file);
}else {
- inputStream = new ByteArrayInputStream(base64EncodedCert.getBytes());
+ inputStream = new ByteArrayInputStream(base64EncodedCertOrFilePath.getBytes());
}
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certificateFactory.generateCertificate(inputStream);
+ Collection extends Certificate> parsedCertificates = certificateFactory.generateCertificates(inputStream);
+ List certificates = new ArrayList<>();
+
+ for (Certificate certificate: parsedCertificates) {
+ certificates.add ((X509Certificate)certificate);
+ }
+ return certificates;
+ // return (X509Certificate) certificateFactory.generateCertificate(inputStream);
}
}
diff --git a/src/main/java/com/axway/ExternalConfigLoader.java b/src/main/java/com/axway/ExternalConfigLoader.java
index 55c28c1..fe082d0 100644
--- a/src/main/java/com/axway/ExternalConfigLoader.java
+++ b/src/main/java/com/axway/ExternalConfigLoader.java
@@ -1,5 +1,6 @@
package com.axway;
+import com.vordel.common.Config;
import com.vordel.common.crypto.PasswordCipher;
import com.vordel.config.ConfigContext;
import com.vordel.config.LoadableModule;
@@ -25,9 +26,9 @@ public class ExternalConfigLoader implements LoadableModule {
private static final Logger log = LogManager.getLogger(ExternalConfigLoader.class);
private final CertHelper certHelper = new CertHelper();
+ private final ExternalInstanceDomainCert externalInstanceDomainCert = new ExternalInstanceDomainCert();
private PasswordCipher passwordCipher;
-
@Override
public void load(LoadableModule arg0, String arg1) {
log.info("loading Password and Certificate Environment variable Module");
@@ -98,11 +99,12 @@ private void updatePassword(EntityStore entityStore) {
String radiusShorthandKey = shorthandKey + "/[RadiusServer]host=" + host + ",port=" + port;
updatePasswordField(entityStore, radiusShorthandKey, "secret", passwordValue, null);
}
-
} else if (key.startsWith("cert_")) {
try {
- X509Certificate certificate = certHelper.parseX509(passwordValue);
- importPublicCertificate(certificate, entityStore);
+ List certificates = certHelper.parseX509(passwordValue);
+ for (X509Certificate certificate:certificates) {
+ importPublicCertificate(certificate, entityStore);
+ }
} catch (CertificateException | FileNotFoundException e) {
Trace.error("Unable to add the certs from Environment variable", e);
}
@@ -120,12 +122,21 @@ private void updatePassword(EntityStore entityStore) {
}
} else if (key.startsWith("cassandraCert")) {
try {
- X509Certificate certificate = certHelper.parseX509(passwordValue);
- String alias = importPublicCertificate(certificate, entityStore);
- if(alias != null) {
- String escapedAlias = ShorthandKeyFinder.escapeFieldValue(alias);
- updateCassandraCert(entityStore, escapedAlias);
+ List certificates = certHelper.parseX509(passwordValue);
+ int index = 0;
+ for (X509Certificate certificate:certificates) {
+ String alias = importPublicCertificate(certificate, entityStore);
+ if(alias != null) {
+ // String escapedAlias = ShorthandKeyFinder.escapeFieldValue(alias);
+ //updateCassandraCert(entityStore, escapedAlias);
+ if(index == 0)
+ updateCassandraCert(entityStore, alias, false);
+ else
+ updateCassandraCert(entityStore, alias, true);
+ index++;
+ }
}
+
} catch (CertificateException | FileNotFoundException e) {
Trace.error("Unable to add Cassandra certificate from Environment variable", e);
}
@@ -133,9 +144,10 @@ private void updatePassword(EntityStore entityStore) {
try {
Trace.info("Updating SSL interface certificate and key");
char[] password = System.getenv("certandkeypassword" + "_" + filterName).toCharArray();
- String alias = importP12(entityStore, passwordValue, password);
- Trace.info("P12 file alias name :" + alias);
- configureP12(entityStore, filterName, alias);
+ String mTLS = System.getenv("certandkeymtls" + "_" + filterName);
+ PKCS12 pkcs12 = importP12(entityStore, passwordValue, password);
+ Trace.info("P12 file alias name :" + pkcs12.getAlias());
+ configureP12(entityStore, filterName, pkcs12, mTLS);
} catch (Exception e) {
Trace.error("Unable to add the p12 from Environment variable", e);
}
@@ -143,14 +155,34 @@ private void updatePassword(EntityStore entityStore) {
try {
Trace.info("Updating Connect to URL client Auth certificate and key");
char[] password = System.getenv("connecttourlcertandkeypassword" + "_" + filterName).toCharArray();
- String alias = importP12(entityStore, passwordValue, password);
+ String alias = importP12(entityStore, passwordValue, password).getAlias();
Trace.info("P12 file alias name :" + alias);
connectToURLConfigureP12(entityStore, filterName, alias);
} catch (Exception e) {
Trace.error("Unable to add the p12 from Environment variable", e);
}
+ } else if (key.startsWith("gatewaytoplogycertandkey_")) {
+ try {
+ Trace.info("Updating Gateway topology certificate");
+ char[] password = System.getenv("gatewaytoplogycertandkeypassword" + "_" + filterName).toCharArray();
+ File file = new File(passwordValue);
+ PKCS12 pkcs12;
+ if(file.exists()){
+ pkcs12 = certHelper.parseP12(file, password);
+ }else {
+ pkcs12 = certHelper.parseP12(passwordValue, password);
+ }
+ File gatewayConfDir = new File(Config.getVDir("VINSTDIR"), "conf");
+ File certsXml = new File(gatewayConfDir, "certs.xml");
+ String caAlias = externalInstanceDomainCert.certsFile(pkcs12, certsXml);
+ File mgmtXml = new File(gatewayConfDir, "mgmt.xml");
+ externalInstanceDomainCert.updateMgmtFile(mgmtXml, caAlias);
+
+ } catch (Exception e) {
+ Trace.error("Unable to add the p12 from Environment variable", e);
}
}
+ }
List credentials = parseCred(ldap, "ldap");
if (!credentials.isEmpty()) {
@@ -171,7 +203,6 @@ private void updatePassword(EntityStore entityStore) {
for (Credential credential : credentials) {
updateSMTP(entityStore, credential);
updateAlertSMTP(entityStore, credential);
-
}
}
}
@@ -302,17 +333,13 @@ private void updateAlertSMTP(EntityStore entityStore, Credential credential) {
}
}
- private void updateCassandraCert(EntityStore entityStore, String escapedAlias) {
+ private void updateCassandraCert(EntityStore entityStore, String alias, boolean append) {
String shorthandKey = "/[CassandraSettings]name=Cassandra Settings";
Entity entity = getEntity(entityStore, shorthandKey);
boolean useSSL = entity.getBooleanValue("useSSL");
if (useSSL) {
- //String certPlaceHolder = "";
- Entity certEntity = getCertEntity(entityStore, escapedAlias);
- PortableESPK portableESPK = PortableESPK.toPortableKey(entityStore, certEntity.getPK());
- // PortableESPK portableESPK = getCertEntity(entityStore, escapedAlias);
- entity.setReferenceField("sslTrustedCerts", portableESPK);
- entityStore.updateEntity(entity);
+ String filedName = "sslTrustedCerts";
+ updateCertEntity(entityStore, entity, alias, filedName, append);
}
}
@@ -348,7 +375,6 @@ private String importPublicCertificate(X509Certificate certificate, EntityStore
Entity certEntity = getCertEntity(entityStore, escapedAlias);
Trace.info("Alias :" + alias + "Escaped alias :"+ escapedAlias);
-
if (certEntity == null) {
Trace.info("Adding cert");
certEntity = EntityStoreDelegate.createDefaultedEntity(entityStore, "Certificate");
@@ -363,18 +389,16 @@ private String importPublicCertificate(X509Certificate certificate, EntityStore
certEntity.setBinaryValue("content", certificate.getEncoded());
entityStore.updateEntity(certEntity);
}
- return escapedAlias;
+ return alias;
} catch (CertificateException e) {
Trace.error("Unable to add the certs from Environment variable", e);
}
return null;
}
- private void configureP12(EntityStore entityStore, String name, String alias) {
+ private void configureP12(EntityStore entityStore, String name, PKCS12 pkcs12, String mTLS) {
String shorthandKey = "/[NetService]name=Service/[HTTP]**/[SSLInterface]name=" + name;
- //ShorthandKeyFinder shorthandKeyFinder = new ShorthandKeyFinder(entityStore);
- //List entities = shorthandKeyFinder.getEntities(shorthandKey);
List entities = getEntities(entityStore, shorthandKey);
if (entities.isEmpty()) {
Trace.error("Listener interface is not available");
@@ -385,7 +409,34 @@ private void configureP12(EntityStore entityStore, String name, String alias) {
}
Entity entity = entities.get(0);
String fieldName = "serverCert";
- updateP12Cert(entityStore, entity, alias, fieldName);
+ String alias = pkcs12.getAlias();
+ updateCertEntity(entityStore, entity, alias, fieldName, false);
+ Trace.info("Mutual auth flag : "+ mTLS);
+ if(mTLS != null && mTLS.equalsIgnoreCase("true")){
+ String clientAuth = entity.getStringValue("clientAuth");
+ Trace.info("Mutual auth configured with flag : "+ clientAuth);
+ if(clientAuth.equals("required") || clientAuth.equals("optional")){
+ trustRootAndIntermediateCerts(entityStore, entity, pkcs12 );
+ }
+ }
+ }
+
+ private void trustRootAndIntermediateCerts(EntityStore entityStore, Entity entity, PKCS12 pkcs12){
+ Certificate[] certificates = pkcs12.getCertificates();
+ Trace.info("Trusting additional certs for mutual auth");
+ Trace.info("Total certificates : "+ certificates.length);
+ for (int i = 1; i < certificates.length; i++) {
+ X509Certificate certificate = (X509Certificate) certificates[i];
+ Principal principal = certificate.getSubjectDN();
+ final String alias = principal.getName();
+ Trace.info("Trusting cert :"+ alias);
+ String fieldName = "caCert";
+ if( i == 1)
+ updateCertEntity(entityStore, entity, alias, fieldName, false);
+ else
+ // Trust more than one certificate for mutual auth
+ updateCertEntity(entityStore, entity, alias, fieldName, true);
+ }
}
private List getEntities(EntityStore entityStore, String shorthandKey){
@@ -393,14 +444,32 @@ private List getEntities(EntityStore entityStore, String shorthandKey){
return shorthandKeyFinder.getEntities(shorthandKey);
}
- private void updateP12Cert(EntityStore entityStore, Entity entity, String alias, String fieldName){
+ private void updateCertEntity(EntityStore entityStore, Entity entity, String alias, String fieldName, boolean append){
String escapedAlias = ShorthandKeyFinder.escapeFieldValue(alias);
Entity certEntity = getCertEntity(entityStore, escapedAlias);
- //Trace.info("Certificate entity set to listener interface "+ certEntity);
+ // Trace.info("Certificate entity set to listener interface "+ certEntity);
PortableESPK portableESPK = PortableESPK.toPortableKey(entityStore, certEntity.getPK());
//Trace.info("Portable : " + portableESPK);
- entity.setReferenceField(fieldName, portableESPK);
+ if(append) {
+ Field field = entity.getField(fieldName);
+ List values = field.getValueList();
+ List cloneVales = new ArrayList<>(values);
+ for (Value value : cloneVales) {
+ PortableESPK espk = (PortableESPK) value.getRef();
+ String certStoreDistinguishedName = espk.getFieldValueOfReferencedEntity("dname");
+ Trace.info(" alias name from Gateway Cert store :" + certStoreDistinguishedName);
+ if (certStoreDistinguishedName.equals(alias)) {
+ Trace.info("Removing existing certs" + alias);
+ values.remove(value);
+ }
+ Trace.info("adding " + alias);
+ values.add(new Value(portableESPK));
+ }
+ field.setValues(values);
+ }else {
+ entity.setReferenceField(fieldName, portableESPK);
+ }
entityStore.updateEntity(entity);
}
@@ -418,7 +487,7 @@ private void connectToURLConfigureP12(EntityStore entityStore, String name, Stri
}
Entity entity = entities.get(0);
String fieldName = "sslUsers";
- updateP12Cert(entityStore, entity, alias, fieldName);
+ updateCertEntity(entityStore, entity, alias, fieldName, false);
}
private Entity getCertEntity(EntityStore entityStore, String alias) {
@@ -434,7 +503,7 @@ private Entity getCertEntity(EntityStore entityStore, String alias) {
}
- private String importP12(EntityStore entityStore, String cert, char[] password) throws Exception {
+ private PKCS12 importP12(EntityStore entityStore, String cert, char[] password) throws Exception {
PKCS12 pkcs12;
File file = new File(cert);
@@ -451,7 +520,6 @@ private String importP12(EntityStore entityStore, String cert, char[] password)
Trace.info("Escaped Certificate alias name : " + escapedAlias);
// Trace.info("Certificate Entity received from entity store : "+ certEntity);
if (certEntity != null) {
- //certEntity.setBinaryValue();
//Updates the existing certificate in the certstore
Trace.info("Updating existing certificate");
for (int i = 0; i < certificates.length; i++) {
@@ -465,15 +533,12 @@ private String importP12(EntityStore entityStore, String cert, char[] password)
X509Certificate certificate = (X509Certificate) certificates[i];
importPublicCertificate(certificate, entityStore);
}
-
}
-
} else {
ESPK rootPK = entityStore.getRootPK();
EntityType group = entityStore.getTypeForName("Certificates");
Collection groups = entityStore.listChildren(rootPK, group);
certEntity = EntityStoreDelegate.createDefaultedEntity(entityStore, "Certificate");
-
for (int i = 0; i < certificates.length; i++) {
if (i == 0) {
Trace.info("Importing Leaf certificate");
@@ -490,9 +555,8 @@ private String importP12(EntityStore entityStore, String cert, char[] password)
importPublicCertificate(certificate, entityStore);
Trace.info("Imported root / intermediate certificate");
}
-
}
}
- return alias;
+ return pkcs12;
}
}
diff --git a/src/main/java/com/axway/ExternalInstanceDomainCert.java b/src/main/java/com/axway/ExternalInstanceDomainCert.java
new file mode 100644
index 0000000..00993ad
--- /dev/null
+++ b/src/main/java/com/axway/ExternalInstanceDomainCert.java
@@ -0,0 +1,170 @@
+package com.axway;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+
+public class ExternalInstanceDomainCert {
+
+ private static final Logger log = LogManager.getLogger(ExternalInstanceDomainCert.class);
+
+
+ public final static String LINE_SEPARATOR = System.getProperty("line.separator");
+ private Base64.Encoder encoder;
+
+ public ExternalInstanceDomainCert() {
+ encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());
+ }
+
+
+ // File certsXml = new File(Config.getVDir("VINSTDIR"), "conf");
+ // File certsXml = new File("src/");
+ // certsXml = new File(certsXml, "certs.xml");
+
+
+ public void updateMgmtFile(File mgmtFile, String CAAlias) throws ParserConfigurationException, IOException, SAXException, TransformerException {
+ if (mgmtFile.exists()) {
+ log.info("Management file mgmt.xml exists");
+ }
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.parse(mgmtFile);
+ NodeList nodeList = document.getElementsByTagName("SSLInterface");
+ Element sslInterface = (Element) nodeList.item(0);
+ NodeList trustedCA = sslInterface.getElementsByTagName("TrustedCA");
+ if (trustedCA.getLength() == 0) {
+ Element trustedCAElement = document.createElement("TrustedCA");
+ trustedCAElement.setAttribute("cert", CAAlias);
+ sslInterface.appendChild(trustedCAElement);
+ }
+ sslInterface.setAttribute("address", "*");
+ NodeList verifyIsLocalNodeManager = sslInterface.getElementsByTagName("VerifyIsLocalNodeManager");
+ if (verifyIsLocalNodeManager.getLength() > 0) {
+ Node node = verifyIsLocalNodeManager.item(0);
+ sslInterface.removeChild(node);
+ }
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(document);
+ FileWriter writer = new FileWriter(mgmtFile);
+ StreamResult result = new StreamResult(writer);
+ transformer.transform(source, result);
+// byte[] data = Files.readAllBytes(Paths.get(mgmtFile.getAbsolutePath()));
+// System.out.println(new String(data));
+
+ }
+
+ public String certsFile(PKCS12 pkcs12, File certsXml) throws IOException, CertificateException {
+
+ String CAAlias = null;
+ if (certsXml.exists()) {
+ log.info("Management file certs.xml exists");
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("");
+ PrivateKey privateKey = pkcs12.getPrivateKey();
+
+ String privateKeyEncoded = encoder.encodeToString(privateKey.getEncoded());
+ Certificate[] certificates = pkcs12.getCertificates();
+ for (Certificate certificate : certificates) {
+ PublicKey publicKey = certificate.getPublicKey();
+ byte[] data = "test".getBytes();
+ byte[] digitalSignature = signData(data, privateKey);
+ if (verifySignature(data, publicKey, digitalSignature)) {
+ createCertificateElement(stringBuilder, pkcs12.getAlias());
+ createPublicKeyElement(stringBuilder, certificate);
+ stringBuilder.append("");
+ stringBuilder.append(privateKeyEncoded);
+ stringBuilder.append("");
+ } else {
+ X509Certificate cert = (X509Certificate) certificate;
+ CAAlias = cert.getSubjectDN().getName();
+ createCertificateElement(stringBuilder, CAAlias);
+ createPublicKeyElement(stringBuilder, certificate);
+ }
+ endCertificateElement(stringBuilder);
+ }
+ stringBuilder.append("");
+ FileOutputStream fileOutputStream = null;
+
+ try {
+ fileOutputStream = new FileOutputStream(certsXml);
+ fileOutputStream.write(stringBuilder.toString().getBytes(StandardCharsets.UTF_8));
+ fileOutputStream.close();
+ } finally {
+ if (fileOutputStream != null) {
+ fileOutputStream.close();
+ }
+ }
+ return CAAlias;
+ }
+
+ public void createCertificateElement(StringBuilder stringBuilder, String alias) {
+ stringBuilder.append("");
+ }
+
+ public void endCertificateElement(StringBuilder stringBuilder) {
+ stringBuilder.append("");
+ }
+
+ public void createPublicKeyElement(StringBuilder stringBuilder, Certificate certificate) throws CertificateEncodingException {
+ stringBuilder.append("");
+ stringBuilder.append(encoder.encodeToString(certificate.getEncoded()));
+ stringBuilder.append("");
+
+ }
+
+
+ public static byte[] signData(byte[] data, PrivateKey key) {
+ Signature signer = null;
+ try {
+ signer = Signature.getInstance("SHA256withRSA");
+ signer.initSign(key);
+ signer.update(data);
+ return (signer.sign());
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static boolean verifySignature(byte[] data, PublicKey key, byte[] sig) {
+ Signature signer = null;
+ try {
+ signer = Signature.getInstance("SHA256withRSA");
+ signer.initVerify(key);
+ signer.update(data);
+ return (signer.verify(sig));
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ }
+}
diff --git a/src/test/java/com/axway/CertHelperTest.java b/src/test/java/com/axway/CertHelperTest.java
index cee12a4..1994e1e 100644
--- a/src/test/java/com/axway/CertHelperTest.java
+++ b/src/test/java/com/axway/CertHelperTest.java
@@ -11,6 +11,7 @@
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.List;
public class CertHelperTest {
@@ -69,11 +70,27 @@ public void testX509() {
try {
- X509Certificate certificate = certHelper.parseX509(cert);
+ X509Certificate certificate = certHelper.parseX509(cert).get(0);
String name = certificate.getSubjectDN().getName();
System.out.println(name);
} catch (CertificateException | FileNotFoundException e) {
e.printStackTrace();
}
}
+
+ @Test
+ public void testCertChain() {
+
+ try {
+
+ List certificates = certHelper.parseX509("src/test/resources/certchain.pem");
+ for (X509Certificate certificate: certificates) {
+ String name = certificate.getSubjectDN().getName();
+ System.out.println(name);
+ }
+
+ } catch (CertificateException | FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/test/java/com/axway/ExternalInstanceDomainCertTest.java b/src/test/java/com/axway/ExternalInstanceDomainCertTest.java
new file mode 100644
index 0000000..5457244
--- /dev/null
+++ b/src/test/java/com/axway/ExternalInstanceDomainCertTest.java
@@ -0,0 +1,55 @@
+package com.axway;
+
+import org.junit.Test;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+public class ExternalInstanceDomainCertTest {
+
+ CertHelper certHelper = new CertHelper();
+ ExternalInstanceDomainCert externalInstanceDomainCert = new ExternalInstanceDomainCert();
+
+ @Test
+ public void testCerts(){
+ try {
+ PKCS12 pkcs12 = certHelper.parseP12(new File(ClassLoader.getSystemResource("topology.p12").getFile()), "".toCharArray());
+ File certsXml = new File("src/");
+ certsXml = new File(certsXml, "certs.xml");
+ externalInstanceDomainCert.certsFile(pkcs12, certsXml);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (UnrecoverableKeyException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testUpdateMgmtFile(){
+ File file = new File("src/mgmt.xml");
+ try {
+ externalInstanceDomainCert.updateMgmtFile(file, "cn=dss");
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (SAXException e) {
+ e.printStackTrace();
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/test/resources/certchain.pem b/src/test/resources/certchain.pem
new file mode 100644
index 0000000..edf7298
--- /dev/null
+++ b/src/test/resources/certchain.pem
@@ -0,0 +1,39 @@
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhICCQCBqBgKx63lZzANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCQVoxEzARBgNVBAcMClNjb3R0c2RhbGUxDjAMBgNVBAoMBUFY
+V0FZMRYwFAYDVQQDDA1DQUNFUlRJRklDQVRFMB4XDTIxMDEyODIzMzAxOFoXDTMx
+MDEyNjIzMzAxOFowVzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRMwEQYDVQQH
+DApTY290dHNkYWxlMQ4wDAYDVQQKDAVBWFdBWTEWMBQGA1UEAwwNQ0FDRVJUSUZJ
+Q0FURTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVg4lsT07yviqti
+qfeT0DZ3kOUfDE2mRDRIlHFM0XnbZyKLFEih5vq+SSHJZQ3B6WX1JY/Ya+srpk0q
+kDV6fU8VyO7auGw6v8hv2UYxIAak4ubgpD+KFlycArGqYFh9pxIepphlj96kaS8j
+pyF7NcRiRoQs39BBx9Qv0sbsyQNBaDa7iJR+MO/tvEiKFjVmdmRKyLcLg4iGGUlj
+QeL2UcHdXhqP2YynKrVYJ+XyFEi4vWQG3xjOzjQeKA5MSHAlYaHmsxtoJ8qIB0M+
++e2qszPBwX1/0ZVTLK6rEccZmc79VPXgL+tLcwYIouPxI0TLkPZtP8c2i5LbPLM4
+VaQLemUCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAcV5Q4Pz8MDJq4uGFazlf2YhR
+PQgcPwjx/snX4PiU4grAmxhkGSH7lNGXHzJChIqToqaCmQsy+r1dRHYvz+9jugdH
+FRvb6LkFovsowSqX2s/b4a8O7xy4I2LUywmw5x18Qs+4E2xbUjK9etPjGcGh2A0c
+c6lGXwr4zsgno9Ab3HJ697lfhIlsW04aKfbYyGHH+QZNSOBl9ntgYJPMEcyoMf1S
+b97wugInnNFAIl4XuNgUEJ+120p4PQBFi32p4hL/vyjiyjGeNkLeYRrsjK7Q/2Vs
+/UxLHkyi75+bBBjFEC/Ua3n8LvZVZSRaltUcbBGaAbZsJIw1IcAPZLBuX0o8cQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDMTCCAhkCCQC6WubUQRFOnTANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCQVoxEzARBgNVBAcMClNjb3R0c2RhbGUxDjAMBgNVBAoMBUFY
+V0FZMRYwFAYDVQQDDA1DQUNFUlRJRklDQVRFMB4XDTIxMDEyODIzMzAzMFoXDTIy
+MDEyMzIzMzAzMFowXjEPMA0GA1UEAwwGZHNzYXBpMQwwCgYDVQQLDANEU1MxEzAR
+BgNVBAcMClNjb3R0c2RhbGUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQKDAVBeHdheTEL
+MAkGA1UECAwCQVowggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQvJuk
+/SSvMBGbRdUNH1ZrZ8whjrhIMGIV80bY3sZHnqqC4eBo9IHn+7ABmEaVlsXMoBD4
+hr+kKnZzi/SXqBr40fcg4X0zZGAaOlpYISi7kVA43f7kyFEbfbnVyjkNBhDKdALV
+JZwtT4xe7dVB9tfNQULvyf6osw42QUipfVn/awcVUt1VLXR8355XV+vy2m46UG+9
+ptHuyxvjn/bGqVSrG06KZCAGZVouR6UkeIYbLFA/Q8FWlduNr73g81APU+T+pfGa
+YrF49xuC8j3mmJgNXscNQCJnKxELwhekouxbnc9wSUjgCdA0v3tg0nbxvP48u9f6
+gY/mgZn1dIL0+/4hAgMBAAEwDQYJKoZIhvcNAQELBQADggEBALkI3sRWSxZLf9Dl
+Cg81DV+zlm7TmJg+PyGctRcAXZWWlhNZUHZC4RT9+SBu8uiw3kMngNrAHd41MGH6
+dRaQj8EWMmrlRlgMpv8QbXCTJE85HksojLS6GXGrV28/WREpOhAE/u5Ln7prTjTz
+tCcz1Jm949OKi+ynIDyOC8QRAlJlBsbvnWcBZwGrOBtfgNnEqS29AVn9USCCoOdx
+K1FGiXGm5kqxsltrge6PZuYzGgq3wnCUosIwNpnXygptdeurvFdSJmetUZLSlovR
+K4EnKbG9NfBVCJwrcdowmthwEUU9ECDGV0QSVh3iRzk/VDCG8eVg6x5MtHIRpLJB
+8AP/mic=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/src/test/resources/topology.p12 b/src/test/resources/topology.p12
new file mode 100644
index 0000000..a68ddb7
Binary files /dev/null and b/src/test/resources/topology.p12 differ