/*
* Copyright 2011 Future Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.krakenapps.ca.msgbus;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Requires;
import org.bouncycastle.util.encoders.Base64;
import org.krakenapps.api.PrimitiveConverter;
import org.krakenapps.ca.CertificateAuthority;
import org.krakenapps.ca.CertificateAuthorityService;
import org.krakenapps.ca.CertificateMetadata;
import org.krakenapps.ca.CertificateRequest;
import org.krakenapps.msgbus.MsgbusException;
import org.krakenapps.msgbus.Request;
import org.krakenapps.msgbus.Response;
import org.krakenapps.msgbus.handler.MsgbusMethod;
import org.krakenapps.msgbus.handler.MsgbusPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@MsgbusPlugin
@Component(name = "ca-plugin")
public class CaPlugin {
private final Logger logger = LoggerFactory.getLogger(CaPlugin.class.getName());
@Requires
private CertificateAuthorityService ca;
@MsgbusMethod
public void issueRootCertificate(Request req, Response resp) {
try {
// parameters
String authorityName = req.getString("authority");
int days = req.getInteger("days");
String cn = req.getString("common_name");
String ou = req.getString("org_unit");
String o = req.getString("org");
String l = req.getString("city");
String st = req.getString("state");
String c = req.getString("country");
String signatureAlgorithm = req.getString("signature_algorithm");
String password = req.getString("password");
String dn = String.format("CN=%s, OU=%s, O=%s, L=%s, ST=%s, C=%s", cn, ou, o, l, st, c);
Date notBefore = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(notBefore);
cal.add(Calendar.DAY_OF_YEAR, days);
Date notAfter = cal.getTime();
// key pair generation
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", "BC");
KeyPair keyPair = keyPairGen.generateKeyPair();
CertificateRequest certReq = CertificateRequest.createSelfSignedCertRequest(keyPair, password, dn, notBefore,
notAfter, signatureAlgorithm);
ca.createAuthority(authorityName, certReq);
CertificateAuthority authority = ca.createAuthority(authorityName, certReq);
X509Certificate cert = authority.getRootCertificate().getCertificate(password);
resp.put("cert", marshal(cert));
} catch (Exception e) {
logger.error("kraken ca: cannot create ca cert", e);
throw new MsgbusException("ca", "general-error");
}
}
@MsgbusMethod
public void issueCertificate(Request req, Response resp) {
try {
String authorityName = req.getString("authority");
// check authority
CertificateAuthority authority = ca.getAuthority(authorityName);
if (authority == null)
throw new MsgbusException("kraken-ca", "authority-not-found");
// generate public/private key pair
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", "BC");
CertificateRequest certReq = new CertificateRequest();
// calculate valid period
int days = req.getInteger("days");
Date notBefore = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(notBefore);
cal.add(Calendar.DAY_OF_YEAR, days);
Date notAfter = cal.getTime();
// build dn
String cn = req.getString("common_name");
String ou = req.getString("org_unit");
String o = req.getString("org");
String l = req.getString("city");
String st = req.getString("state");
String c = req.getString("country");
// set
certReq.setSubjectDn(String.format("CN=%s, OU=%s, O=%s, L=%s, ST=%s, C=%s", cn, ou, o, l, st, c));
certReq.setKeyPair(keyPairGen.generateKeyPair());
certReq.setSignatureAlgorithm(req.getString("signature_algorithm"));
certReq.setKeyPassword(req.getString("password"));
certReq.setNotBefore(notBefore);
certReq.setNotAfter(notAfter);
authority.issueCertificate(certReq);
} catch (MsgbusException e) {
throw e;
} catch (Exception e) {
logger.error("kraken ca: cannot create cert", e);
throw new MsgbusException("ca", "general-error");
}
}
@MsgbusMethod
public void getRootCertificates(Request req, Response resp) {
List<Object> l = new ArrayList<Object>();
for (CertificateAuthority authority : ca.getAuthorities()) {
CertificateMetadata cm = authority.getRootCertificate();
l.add(PrimitiveConverter.serialize(cm));
}
resp.put("root_certs", l);
}
@MsgbusMethod
public void getCertificates(Request req, Response resp) {
String authorityName = req.getString("authority");
// check authority
CertificateAuthority authority = ca.getAuthority(authorityName);
if (authority == null)
throw new MsgbusException("kraken-ca", "authority-not-found");
List<Object> l = new LinkedList<Object>();
for (CertificateMetadata cm : authority.getCertificates()) {
l.add(PrimitiveConverter.serialize(cm));
}
resp.put("certs", l);
}
@MsgbusMethod
public void getCertificate(Request req, Response resp) {
try {
String authorityName = req.getString("authority");
String serial = req.getString("serial");
// check authority
CertificateAuthority authority = ca.getAuthority(authorityName);
if (authority == null)
throw new MsgbusException("kraken-ca", "authority-not-found");
CertificateMetadata cm = authority.findCertificate("serial", serial);
resp.put("cert", cm == null ? null : PrimitiveConverter.serialize(cm));
} catch (Exception e) {
logger.error("kraken ca: cannot get certificate", e);
throw new MsgbusException("ca", "general-error");
}
}
@MsgbusMethod
public void getPfxFile(Request req, Response resp) {
String authorityName = req.getString("authority");
String serial = req.getString("serial");
// check authority
CertificateAuthority authority = ca.getAuthority(authorityName);
if (authority == null)
throw new MsgbusException("kraken-ca", "authority-not-found");
CertificateMetadata cm = authority.findCertificate("serial", serial);
if (cm == null)
throw new MsgbusException("kraken-ca", "certificate-not-found");
byte[] encoded = Base64.encode(cm.getBinary());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < encoded.length; i++)
sb.append((char) encoded[i]);
resp.put("pfx", sb.toString());
}
private Map<String, Object> marshal(X509Certificate cert) {
Map<String, Object> m = new HashMap<String, Object>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
m.put("type", cert.getType());
m.put("version", cert.getVersion());
m.put("serial", cert.getSerialNumber());
m.put("issuer", cert.getIssuerX500Principal().getName());
m.put("subject", cert.getSubjectX500Principal().getName());
m.put("not_before", dateFormat.format(cert.getNotBefore()));
m.put("not_after", dateFormat.format(cert.getNotAfter()));
m.put("public_key", cert.getPublicKey());
m.put("signature_algorithm", cert.getSigAlgName());
m.put("signature", toHexString(cert.getSignature()));
return m;
}
private String toHexString(byte[] b) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < b.length; i++)
sb.append(String.format("%02x", b[i]));
return sb.toString();
}
}