/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.plugins;
import com.eviware.soapui.SoapUI;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.Provider;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
public final class ProductBodyguard extends Provider {
private X509Certificate providerCert = null;
public ProductBodyguard() {
super("SoapUIOSPluginSignChecker", 1.0, "Plugin signature validity checker");
}
private static X509Certificate setupProviderCert()
throws IOException, CertificateException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate) cf.generateCertificate(ProductBodyguard.class.getResourceAsStream("/com/eviware/soapui/plugins/PublicKey.key"));
}
public final synchronized boolean isKnown(File plugin) {
JarVerifier jv = new JarVerifier(plugin);
try {
if (providerCert == null) {
providerCert = setupProviderCert();
}
jv.verify(providerCert);
} catch (Exception e) {
SoapUI.logError(e);
return false;
}
return true;
}
private class JarVerifier {
private JarFile jarFile = null;
JarVerifier(File jarURL) {
try {
jarFile = new JarFile(jarURL);
} catch (IOException e) {
SoapUI.logError(e);
}
}
public void verify(X509Certificate targetCert)
throws IOException {
if (targetCert == null) {
throw new SecurityException("The certificate is not specified.");
}
try {
if (jarFile == null) {
throw new SecurityException("The plugin is not accessible.");
}
} catch (Exception ex) {
SecurityException se = new SecurityException();
se.initCause(ex);
throw se;
}
Vector<JarEntry> entriesVec = new Vector<>();
Manifest man = jarFile.getManifest();
if (man == null) {
throw new SecurityException("The plugin '" + jarFile.getName() + "' is not signed");
}
byte[] buffer = new byte[8192];
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry je = (JarEntry) entries.nextElement();
if (je.isDirectory()) {
continue;
}
entriesVec.addElement(je);
InputStream is = jarFile.getInputStream(je);
int n;
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
}
is.close();
}
Enumeration e = entriesVec.elements();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
Certificate[] certs = je.getCertificates();
if ((certs == null) || (certs.length == 0)) {
if (!je.getName().startsWith("META-INF")) {
throw new SecurityException("The plugin '" + jarFile.getName() + "' has unsigned class files.");
}
} else {
int startIndex = 0;
X509Certificate[] certChain;
boolean signedAsExpected = false;
while ((certChain = getAChain(certs, startIndex)) != null) {
if (certChain[0].equals(targetCert)) {
signedAsExpected = true;
break;
}
startIndex += certChain.length;
}
if (!signedAsExpected) {
throw new SecurityException("The plugin '" + jarFile.getName() + "' is not signed by SmartBear Software");
}
}
}
}
private X509Certificate[] getAChain(Certificate[] certs, int startIndex) {
if (startIndex > certs.length - 1) {
return null;
}
int i;
for (i = startIndex; i < certs.length - 1; i++) {
if (!((X509Certificate) certs[i + 1]).getSubjectDN().
equals(((X509Certificate) certs[i]).getIssuerDN())) {
break;
}
}
int certChainSize = (i - startIndex) + 1;
X509Certificate[] ret = new X509Certificate[certChainSize];
for (int j = 0; j < certChainSize; j++) {
ret[j] = (X509Certificate) certs[startIndex + j];
}
return ret;
}
protected void finalize() throws Throwable {
jarFile.close();
}
}
}