/*******************************************************************************
* Copyright (c) 2011, 2016 Eurotech and/or its affiliates
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eurotech
*******************************************************************************/
package org.eclipse.kura.web.server;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.kura.KuraException;
import org.eclipse.kura.certificate.CertificatesService;
import org.eclipse.kura.ssl.SslManagerService;
import org.eclipse.kura.web.server.util.ServiceLocator;
import org.eclipse.kura.web.shared.GwtKuraErrorCode;
import org.eclipse.kura.web.shared.GwtKuraException;
import org.eclipse.kura.web.shared.model.GwtXSRFToken;
import org.eclipse.kura.web.shared.service.GwtCertificatesService;
public class GwtCertificatesServiceImpl extends OsgiRemoteServiceServlet implements GwtCertificatesService {
/**
*
*/
private static final long serialVersionUID = 7402961266449489433L;
@Override
public Integer storePublicPrivateKeys(GwtXSRFToken xsrfToken, String privateKey, String publicKey, String password,
String alias) throws GwtKuraException {
checkXSRFToken(xsrfToken);
try {
// Remove header if exists
String key = privateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("\n", "");
key = key.replace("-----END PRIVATE KEY-----", "");
Object convertedData = null;
try {
Class<?> clazz = Class.forName("javax.xml.bind.DatatypeConverter");
Method method = clazz.getMethod("parseBase64Binary", String.class);
convertedData = method.invoke(null, key);
} catch (ClassNotFoundException e) {
convertedData = base64DecodeJava8(key);
} catch (LinkageError e) {
convertedData = base64DecodeJava8(key);
} catch (Exception e) {
throw new GwtKuraException(GwtKuraErrorCode.INTERNAL_ERROR, e);
}
byte[] conversion = (byte[]) convertedData;
// Parse Base64 - after PKCS8
PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(conversion);
// Create RSA key
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(specPriv);
Certificate[] certs = parsePublicCertificates(publicKey);
if (privKey == null) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT);
} else {
char[] privateKeyPassword = new char[0];
if (password != null) {
privateKeyPassword = password.toCharArray();
}
SslManagerService sslService = ServiceLocator.getInstance().getService(SslManagerService.class);
sslService.installPrivateKey(alias, privKey, privateKeyPassword, certs);
}
return 1;
} catch (UnsupportedEncodingException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (GeneralSecurityException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (IOException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
}
}
@Override
public Integer storeSSLPublicChain(GwtXSRFToken xsrfToken, String publicKeys, String alias)
throws GwtKuraException {
checkXSRFToken(xsrfToken);
try {
X509Certificate[] certs = parsePublicCertificates(publicKeys);
if (certs.length == 0) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT);
} else {
SslManagerService sslService = ServiceLocator.getInstance().getService(SslManagerService.class);
boolean leafAssigned = false;
for (X509Certificate cert : certs) {
if (!leafAssigned && (cert.getBasicConstraints() == -1
|| cert.getKeyUsage() != null && !cert.getKeyUsage()[5])) { // certificate is leaf
sslService.installTrustCertificate("ssl-" + alias, cert);
leafAssigned = true;
} else { // Certificate is CA.
// http://stackoverflow.com/questions/12092457/how-to-check-if-x509certificate-is-ca-certificate
String certificateAlias = "ca-" + cert.getSerialNumber().toString();
sslService.installTrustCertificate(certificateAlias, cert);
}
}
}
return certs.length;
} catch (CertificateException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (UnsupportedEncodingException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (GeneralSecurityException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (IOException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
}
}
@Override
public Integer storeApplicationPublicChain(GwtXSRFToken xsrfToken, String publicKeys, String alias)
throws GwtKuraException {
checkXSRFToken(xsrfToken);
try {
X509Certificate[] certs = parsePublicCertificates(publicKeys);
if (certs.length == 0) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT);
} else {
CertificatesService certificateService = ServiceLocator.getInstance()
.getService(CertificatesService.class);
boolean leafAssigned = false;
for (X509Certificate cert : certs) {
if (!leafAssigned && (cert.getBasicConstraints() == -1
|| cert.getKeyUsage() != null && !cert.getKeyUsage()[5])) { // certificate is leaf
certificateService.storeCertificate(cert, "bundle-" + alias);
leafAssigned = true;
} else { // Certificate is CA.
// http://stackoverflow.com/questions/12092457/how-to-check-if-x509certificate-is-ca-certificate
String certificateAlias = "bundle-" + cert.getSerialNumber().toString();
certificateService.storeCertificate(cert, certificateAlias);
}
}
}
return certs.length;
} catch (CertificateException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (UnsupportedEncodingException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
} catch (KuraException e) {
throw new GwtKuraException(GwtKuraErrorCode.ILLEGAL_ARGUMENT, e);
}
}
private X509Certificate[] parsePublicCertificates(String publicKey)
throws CertificateException, UnsupportedEncodingException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> publicCertificates = certFactory
.generateCertificates(new ByteArrayInputStream(publicKey.getBytes("UTF-8")));
Iterator<? extends Certificate> certIterator = publicCertificates.iterator();
X509Certificate[] certs = new X509Certificate[publicCertificates.size()];
int i = 0;
while (certIterator.hasNext()) {
X509Certificate cert = (X509Certificate) certIterator.next();
certs[i] = cert;
i++;
}
return certs;
}
private Object base64DecodeJava8(String key) throws GwtKuraException {
Object convertedData = null;
try {
Class<?> clazz = Class.forName("java.util.Base64");
Method decoderMethod = clazz.getMethod("getDecoder", (Class<?>[]) null);
Object decoder = decoderMethod.invoke(null, new Object[0]);
Class<?> Base64Decoder = Class.forName("java.util.Base64$Decoder");
Method decodeMethod = Base64Decoder.getMethod("decode", String.class);
convertedData = decodeMethod.invoke(decoder, key);
} catch (Exception e1) {
throw new GwtKuraException(GwtKuraErrorCode.INTERNAL_ERROR, e1);
}
return convertedData;
}
}