/**
Copyright 2014-2015 Center for TeleInFrastruktur (CTIF), Aalborg University
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 eu.betaas.taas.securitymanager.core.service.impl;
import java.security.Security;
import java.util.Date;
import org.apache.log4j.Logger;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import eu.betaas.taas.securitymanager.authentication.service.IEncryptDecryptService;
import eu.betaas.taas.securitymanager.authentication.service.IGatewayEcmqvExtService;
import eu.betaas.taas.securitymanager.authentication.service.IGatewayEcmqvIntService;
import eu.betaas.taas.securitymanager.certificate.service.IGatewayCertificateService;
import eu.betaas.taas.securitymanager.common.certificate.utils.PKCS12Utils;
import eu.betaas.taas.securitymanager.common.model.BcCredential;
import eu.betaas.taas.securitymanager.common.mqv.EcmqvMessage;
//import eu.betaas.taas.securitymanager.core.activator.SecMTaasCoreActivator;
import eu.betaas.taas.securitymanager.core.service.ISecGWCommService;
import eu.betaas.taas.securitymanager.core.utils.CoreBetaasBus;
/**
* Class implementation of ISecGWCommService interface
*
* @author Bayu Anggorojati [ba@es.aau.dk]
* Center for TeleInFrastruktur, Aalborg University, Denmark
*
*/
public class SecureGWCommService implements ISecGWCommService {
/** The Logger */
Logger log = Logger.getLogger("betaas.taas.securitymanager");
/** Reference to Bundle Context from blueprint */
private BundleContext context;
/** Reference to Ecmqv Internal service from blueprint */
private IGatewayEcmqvIntService gwEcmqvIntService;
/** Reference to GWCertificateService from blueprint */
private IGatewayCertificateService gwCertificateService;
/** Reference to EncryptDecryptService from blueprint */
private IEncryptDecryptService encryptService;
/** Tracker of GWEcmqvExtService */
private ServiceTracker ecmqvExtTracker;
/** This GW ID */
private String mGwId;
/** Class that handles BETaaS BUS in authentication bundle */
private CoreBetaasBus bus;
/**
* Initial setup method to initialize betaas bus service
*/
public void setup(){
// set the GW ID
bus = new CoreBetaasBus(context);
}
public SecureGWCommService(){
// this.coreActivator = coreActivator;
// this.context = coreActivator.getContext();
}
public boolean deriveSharedKeys(String gwDestId) throws Exception {
Security.addProvider(new BouncyCastleProvider());
boolean result = false;
log.info("Start deriving shared keys");
bus.sendData("Start deriving shared keys", "info", "SecM");
BcCredential myCertStore = null;
// generate an ephemeral KeyPair
AsymmetricCipherKeyPair myEphKp = gwEcmqvIntService.
generateEphemeralKeyPair();
// initiate the ECMQV procedure...
// first load the credential and then the certificate of this GW
myCertStore = gwCertificateService.loadMyCertificate(PKCS12Utils.GW_CERT);
X509CertificateHolder myCert = null;
if(myCertStore != null){
myCert = (X509CertificateHolder) myCertStore.getCertificateChain()[0];
}
// then, invoke the initEcmqv method to other GW, by retrieving the
// external ECMQV service first
EcmqvMessage eMsg = null;
IGatewayEcmqvExtService ecmqvExtServ = null;
// initializing service tracker of GWEcmqvExtService
ecmqvExtTracker = new ServiceTracker(
context, IGatewayEcmqvExtService.class.getName(), null);
ecmqvExtTracker.open();
// give time to the tracker to find CertificateExtService
Thread.sleep(2500);
ServiceReference[] refs = ecmqvExtTracker.getServiceReferences();
// iterating through the service references
for(ServiceReference ref : refs){
// check if gatewayId of remote GW equals to gwDestId of this GW
if(ref.getProperty("gwId").equals(gwDestId)){
log.debug("Found ExtEcmqv service of the GW destination ID");
bus.sendData("Found ExtEcmqv service of the GW destination ID", "debug",
"SecM");
ecmqvExtServ = (IGatewayEcmqvExtService) context.getService(ref);
}
}
if(ecmqvExtServ != null){
// the actual invocation of initEcmqv
eMsg = ecmqvExtServ.initEcmqv(
((ECPublicKeyParameters)myEphKp.getPublic()).getQ().normalize().getXCoord().toBigInteger().toByteArray(), // the X-coordinate of EC public key param.
((ECPublicKeyParameters)myEphKp.getPublic()).getQ().normalize().getYCoord().toBigInteger().toByteArray(), // the Y-coordinate of EC public key param.
myCert.getEncoded());
}
// upon receiving the eMsg, verify it and calculate the MAC 3
byte[] mac3 = null;
if(eMsg != null){
mac3 = gwEcmqvIntService.responseEcmqv(eMsg);
}
// upon successful verification of eMsg which results in MAC 3, send MAC 3
// to the other GW
if(mac3!=null && ecmqvExtServ!=null){
long sendLast = ecmqvExtServ.lastEcmqv(mac3, mGwId);
// set the expire time and k2 at the catalog of the internal interface
gwEcmqvIntService.setKeyAndExpireTime(gwDestId, sendLast);
// closing the service tracker
ecmqvExtTracker.close();
if(sendLast >= 0){
log.info("the MAC 3 is correctly confirmed");
bus.sendData("the MAC 3 is correctly confirmed", "info", "SecM");
result = true;
}
else{
log.info("the MAC 3 isn't valid!!");
bus.sendData("the MAC 3 isn't valid", "warning", "SecM");
}
}
return result;
}
public String doEncryptData(String gwDestId, String data){
//check if the key associated with gwDestId exists and is not expired
boolean isK2 = false;
byte[] k2 = gwEcmqvIntService.getK2(gwDestId);
if(k2==null){
log.debug("k2 is not found, need to initiate key agreement protocol.");
// initiate ECMQV protocol
try {
isK2 = deriveSharedKeys(gwDestId);
if(isK2)
k2 = gwEcmqvIntService.getK2(gwDestId);
} catch (Exception e) {
// TODO Auto-generated catch block
log.error("Exception in ECMQV key agreement protocol: "+e.getMessage());
bus.sendData("Exception in ECMQV key agreement protocol", "error",
"SecM");
return null;
}
}
else{
// if the key has been expired
if((new Date()).getTime() >= gwEcmqvIntService.getExpireTime(gwDestId)){
log.debug("k2 is expired, need to initiate key agreement protocol.");
// again initiate ECMQV protocol
try {
isK2 = deriveSharedKeys(gwDestId);
if(isK2)
k2 = gwEcmqvIntService.getK2(gwDestId);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
isK2 = true;
}
// start the encryption
log.debug("start encrypting data...");
log.debug("isK2: "+isK2);
if(isK2)
return encryptService.doEncryption(k2, data);
else{
log.warn("There is problem with secret key (k2) associated with GW ID: "
+gwDestId);
bus.sendData("There is problem with secret key (k2) associated with GW "+
"ID: " +gwDestId, "warning", "SecM");
return null;
}
}
public String doDecryptData(String gwOriId, String encrypted){
//check if the key associated with gwDestId exists and is not expired
boolean isK2 = false;
byte[] k2 = gwEcmqvIntService.getK2(gwOriId);
// we can assume that k2 exists since the received encrypted message uses k2
// now just check if k2 is not expired
if((new Date()).getTime() >= gwEcmqvIntService.getExpireTime(gwOriId)){
// initiate ECMQV protocol
try {
isK2 = deriveSharedKeys(gwOriId);
if(isK2)
k2 = gwEcmqvIntService.getK2(gwOriId);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else{
isK2 = true;
}
// start the decryption
if(isK2)
return encryptService.doDecryption(k2, encrypted);
else{
log.warn("There is problem with secret key (k2) associated with GW ID: "
+ gwOriId);
bus.sendData("There is problem with secret key (k2) associated with GW "+
"ID: " +gwOriId, "warning", "SecM");
return null;
}
}
/**
* Blueprint set reference to BundleContext
* @param context
*/
public void setContext(BundleContext context) {
this.context = context;
log.debug("Got the BundleContext...");
}
/**
* Blueprint set reference to IGatewayEcmqvIntService
* @param gwEcmqvIntService
*/
public void setGwEcmqvIntService(IGatewayEcmqvIntService gwEcmqvIntService) {
this.gwEcmqvIntService = gwEcmqvIntService;
log.debug("Got the GWEcmqvIntService...");
}
/**
* Blueprint set reference to IGatewayCertificateService
* @param gwCertificateService
*/
public void setGwCertificateService(
IGatewayCertificateService gwCertificateService) {
this.gwCertificateService = gwCertificateService;
log.debug("Got the GWCertificateService...");
}
public void setEncryptDecryptService(
IEncryptDecryptService encryptDecryptService){
this.encryptService = encryptDecryptService;
log.debug("Got the EncryptDecryptService...");
}
/**
* Blueprint set reference to gwId of this GW
* @param gwId
*/
public void setGwId(String gwId) {
this.mGwId = gwId;
}
}