Bläddra i källkod

Added PreCharge Timer, CableCheck Timer to TimeRestrictions.java and added handling for those timers in EVCC package.
Minor bugfixing with regards to genChallenge in AuthorizationReq

Marc Mültin 8 år sedan
förälder
incheckning
af1f3480e0

+ 11 - 0
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/evController/DummyEVController.java

@@ -36,6 +36,7 @@ import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVChargeParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingProfileType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVChargeParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVErrorCodeType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVPowerDeliveryParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVStatusType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PMaxScheduleEntryType;
@@ -319,4 +320,14 @@ public class DummyEVController implements IACEVController, IDCEVController {
 	public void setChargingLoopCounter(int chargingLoopCounter) {
 		this.chargingLoopCounter = chargingLoopCounter;
 	}
+
+	@Override
+	public DCEVPowerDeliveryParameterType getEVPowerDeliveryParameter() {
+		DCEVPowerDeliveryParameterType dcEvPowerDeliveryParameter = new DCEVPowerDeliveryParameterType();
+		dcEvPowerDeliveryParameter.setBulkChargingComplete(false);
+		dcEvPowerDeliveryParameter.setChargingComplete(false);
+		dcEvPowerDeliveryParameter.setDCEVStatus(getDCEVStatus());
+		
+		return dcEvPowerDeliveryParameter;
+	}
 }

+ 8 - 0
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/evController/IDCEVController.java

@@ -26,6 +26,7 @@ package org.v2gclarity.risev2g.evcc.evController;
 import javax.xml.bind.JAXBElement;
 
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVChargeParameterType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVPowerDeliveryParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVStatusType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PhysicalValueType;
 
@@ -107,4 +108,11 @@ public interface IDCEVController extends IEVController {
 	 * @return The estimated time given as a PhysicalValueType
 	 */
 	public PhysicalValueType getRemainingTimeToBulkSOC();
+	
+	
+	/**
+	 * Returns the DC_EVPowerDeliverParameter
+	 * @return The DC_EVPowerDeliverParameter
+	 */
+	public DCEVPowerDeliveryParameterType getEVPowerDeliveryParameter();
 }

+ 15 - 2
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/ClientState.java

@@ -27,6 +27,9 @@ import java.security.KeyStore;
 import java.util.Arrays;
 import java.util.ListIterator;
 
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
 import org.v2gclarity.risev2g.evcc.evController.DummyEVController;
 import org.v2gclarity.risev2g.evcc.evController.IACEVController;
 import org.v2gclarity.risev2g.evcc.evController.IDCEVController;
@@ -38,6 +41,7 @@ import org.v2gclarity.risev2g.shared.misc.State;
 import org.v2gclarity.risev2g.shared.utils.ByteUtils;
 import org.v2gclarity.risev2g.shared.utils.MiscUtils;
 import org.v2gclarity.risev2g.shared.utils.SecurityUtils;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVSEStatusType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.AuthorizationReqType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.AuthorizationResType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.BodyBaseType;
@@ -53,7 +57,9 @@ import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingSessionType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingStatusResType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.CurrentDemandReqType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.CurrentDemandResType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.DCEVPowerDeliveryParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EMAIDType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSENotificationType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.MessageHeaderType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.MeteringReceiptResType;
@@ -418,9 +424,16 @@ public abstract class ClientState extends State {
 		powerDeliveryReq.setChargeProgress(chargeProgress);
 		powerDeliveryReq.setSAScheduleTupleID(getCommSessionContext().getEvController().getChosenSAScheduleTupleID());	
 		
-		// Optionally set DC_EVPowerDeliveryParameter if in DC charging mode
+		// Set DC_EVPowerDeliveryParameter if in DC charging mode
 		if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
-			
+			/*
+			 * The MessageHandler method getJAXBElement() cannot be used here because of the difference in the
+			 * class name (DCEVPowerDeliveryParameter) and the name in the XSD (DC_EVPowerDeliveryParameter)
+			 */
+			JAXBElement jaxbDcEvPowerDeliveryParameter = new JAXBElement(new QName("urn:iso:15118:2:2013:MsgDataTypes", "DC_EVPowerDeliveryParameter"), 
+					DCEVPowerDeliveryParameterType.class, 
+					((IDCEVController) getCommSessionContext().getEvController()).getEVPowerDeliveryParameter());
+			powerDeliveryReq.setEVPowerDeliveryParameter(jaxbDcEvPowerDeliveryParameter);
 		}
 		
 		return powerDeliveryReq;

+ 42 - 12
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/WaitForAuthorizationRes.java

@@ -23,16 +23,20 @@
  *******************************************************************************/
 package org.v2gclarity.risev2g.evcc.states;
 
+import java.util.concurrent.TimeUnit;
+
 import org.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
 import org.v2gclarity.risev2g.shared.enumerations.GlobalValues;
 import org.v2gclarity.risev2g.shared.enumerations.V2GMessages;
 import org.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
 import org.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
+import org.v2gclarity.risev2g.shared.misc.TimeRestrictions;
 import org.v2gclarity.risev2g.shared.utils.SecurityUtils;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.AuthorizationReqType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.AuthorizationResType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscoveryReqType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSEProcessingType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.V2GMessage;
 
 public class WaitForAuthorizationRes extends ClientState {
@@ -49,6 +53,11 @@ public class WaitForAuthorizationRes extends ClientState {
 					(AuthorizationResType) v2gMessageRes.getBody().getBodyElement().getValue();
 			
 			if (authorizationRes.getEVSEProcessing().equals(EVSEProcessingType.FINISHED)) {
+				getLogger().debug("EVSEProcessing was set to FINISHED");
+				
+				getCommSessionContext().setOngoingTimer(0L);
+				getCommSessionContext().setOngoingTimerActive(false);
+				
 				ChargeParameterDiscoveryReqType chargeParameterDiscoveryReq = getChargeParameterDiscoveryReq();
 			
 				/*
@@ -59,19 +68,40 @@ public class WaitForAuthorizationRes extends ClientState {
 				
 				return getSendMessage(chargeParameterDiscoveryReq, V2GMessages.CHARGE_PARAMETER_DISCOVERY_RES);
 			} else {
-				// Set xml reference element
-				AuthorizationReqType authorizationReq = getAuthorizationReq(null);
-				getXMLSignatureRefElements().put(
-						authorizationReq.getId(), 
-						SecurityUtils.generateDigest(getMessageHandler().getJaxbElement(authorizationReq)));
+				getLogger().debug("EVSEProcessing was set to ONGOING");
+				
+				if (getCommSessionContext().isOngoingTimerActive()) {
+					long elapsedTime = System.nanoTime() - getCommSessionContext().getOngoingTimer();
+					long elapsedTimeInMs = TimeUnit.MILLISECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
+					
+					if (elapsedTimeInMs > TimeRestrictions.V2G_EVCC_ONGOING_TIMEOUT) 
+						return new TerminateSession("Ongoing timer timed out for AuthorizationReq");
+				} else {
+					getCommSessionContext().setOngoingTimer(System.nanoTime());
+					getCommSessionContext().setOngoingTimerActive(true);
+				}
+					
+				AuthorizationReqType authorizationReq = null;
 				
-				// Set signing private key
-				setSignaturePrivateKey(SecurityUtils.getPrivateKey(
-						SecurityUtils.getKeyStore(
-								GlobalValues.EVCC_KEYSTORE_FILEPATH.toString(),
-								GlobalValues.PASSPHRASE_FOR_CERTIFICATES_AND_KEYS.toString()), 
-						GlobalValues.ALIAS_CONTRACT_CERTIFICATE.toString())
-				);
+				if (getCommSessionContext().getSelectedPaymentOption().equals(PaymentOptionType.CONTRACT) && 
+					getCommSessionContext().isTlsConnection()) {
+					authorizationReq = getAuthorizationReq(getCommSessionContext().getSentGenChallenge());
+					
+					// Set xml reference element
+					getXMLSignatureRefElements().put(
+							authorizationReq.getId(), 
+							SecurityUtils.generateDigest(getMessageHandler().getJaxbElement(authorizationReq)));
+					
+					// Set signing private key
+					setSignaturePrivateKey(SecurityUtils.getPrivateKey(
+							SecurityUtils.getKeyStore(
+									GlobalValues.EVCC_KEYSTORE_FILEPATH.toString(),
+									GlobalValues.PASSPHRASE_FOR_CERTIFICATES_AND_KEYS.toString()), 
+							GlobalValues.ALIAS_CONTRACT_CERTIFICATE.toString())
+					);
+				} else {
+					authorizationReq = getAuthorizationReq(null);
+				}
 				
 				return getSendMessage(authorizationReq, V2GMessages.AUTHORIZATION_RES);
 			}

+ 17 - 0
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/WaitForCableCheckRes.java

@@ -23,11 +23,14 @@
  *******************************************************************************/
 package org.v2gclarity.risev2g.evcc.states;
 
+import java.util.concurrent.TimeUnit;
+
 import org.v2gclarity.risev2g.evcc.evController.IDCEVController;
 import org.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
 import org.v2gclarity.risev2g.shared.enumerations.V2GMessages;
 import org.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
 import org.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
+import org.v2gclarity.risev2g.shared.misc.TimeRestrictions;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.CableCheckResType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.EVSEProcessingType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PreChargeReqType;
@@ -56,10 +59,24 @@ public class WaitForCableCheckRes extends ClientState {
 				preChargeReq.setEVTargetCurrent(dcEvController.getTargetCurrent());
 				preChargeReq.setEVTargetVoltage(dcEvController.getTargetVoltage());
 				
+				getCommSessionContext().setOngoingTimer(System.nanoTime());
+				getCommSessionContext().setOngoingTimerActive(true);
+				
 				return getSendMessage(preChargeReq, V2GMessages.PRE_CHARGE_RES);
 			} else {
 				getLogger().debug("EVSEProcessing was set to ONGOING");
 				
+				if (getCommSessionContext().isOngoingTimerActive()) {
+					long elapsedTime = System.nanoTime() - getCommSessionContext().getOngoingTimer();
+					long elapsedTimeInMs = TimeUnit.MILLISECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
+					
+					if (elapsedTimeInMs > TimeRestrictions.V2G_EVCC_CABLE_CHECK_TIMEOUT) 
+						return new TerminateSession("CableCheck timer timed out for CableCheckReq");
+				} else {
+					getCommSessionContext().setOngoingTimer(System.nanoTime());
+					getCommSessionContext().setOngoingTimerActive(true);
+				}
+				
 				return getSendMessage(getCableCheckReq(), V2GMessages.CABLE_CHECK_RES);
 			}
 		} else {

+ 25 - 2
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/WaitForChargeParameterDiscoveryRes.java

@@ -26,6 +26,7 @@ package org.v2gclarity.risev2g.evcc.states;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
 import org.v2gclarity.risev2g.shared.enumerations.CPStates;
@@ -33,6 +34,7 @@ import org.v2gclarity.risev2g.shared.enumerations.GlobalValues;
 import org.v2gclarity.risev2g.shared.enumerations.V2GMessages;
 import org.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
 import org.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
+import org.v2gclarity.risev2g.shared.misc.TimeRestrictions;
 import org.v2gclarity.risev2g.shared.utils.SecurityUtils;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ACEVSEChargeParameterType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeParameterDiscoveryResType;
@@ -60,8 +62,25 @@ public class WaitForChargeParameterDiscoveryRes extends ClientState {
 			
 			if (chargeParameterDiscoveryRes.getEVSEProcessing().equals(EVSEProcessingType.ONGOING)) {
 				getLogger().debug("EVSEProcessing was set to ONGOING");
+				
+				if (getCommSessionContext().isOngoingTimerActive()) {
+					long elapsedTime = System.nanoTime() - getCommSessionContext().getOngoingTimer();
+					long elapsedTimeInMs = TimeUnit.MILLISECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
+					
+					if (elapsedTimeInMs > TimeRestrictions.V2G_EVCC_ONGOING_TIMEOUT) 
+						return new TerminateSession("Ongoing timer timed out for ChargeParameterDiscoveryReq");
+				} else {
+					getCommSessionContext().setOngoingTimer(System.nanoTime());
+					getCommSessionContext().setOngoingTimerActive(true);
+				}
+				
 				return getSendMessage(getCommSessionContext().getChargeParameterDiscoveryReq(), V2GMessages.CHARGE_PARAMETER_DISCOVERY_RES);
 			} else {
+				getLogger().debug("EVSEProcessing was set to FINISHED");
+				
+				getCommSessionContext().setOngoingTimer(0L);
+				getCommSessionContext().setOngoingTimerActive(false);
+				
 				// Check for the EVSENotification
 				EVSENotificationType evseNotification = null;
 				
@@ -111,9 +130,13 @@ public class WaitForChargeParameterDiscoveryRes extends ClientState {
 							return getSendMessage(getPowerDeliveryReq(ChargeProgressType.START), V2GMessages.POWER_DELIVERY_RES);
 						} else if (getCommSessionContext().getRequestedEnergyTransferMode().toString().startsWith("DC")) {
 							// CP state C signaling BEFORE sending CableCheckReq message in DC
-							if (getCommSessionContext().getEvController().setCPState(CPStates.STATE_C))
+							if (getCommSessionContext().getEvController().setCPState(CPStates.STATE_C)) {
+								// Set timer for CableCheck
+								getCommSessionContext().setOngoingTimer(System.nanoTime());
+								getCommSessionContext().setOngoingTimerActive(true);
+							
 								return getSendMessage(getCableCheckReq(), V2GMessages.CABLE_CHECK_RES);
-							else
+							} else
 								return new TerminateSession("CP state C not ready (current state = " + 
 										getCommSessionContext().getEvController().getCPState() +
 										")");

+ 3 - 0
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/WaitForPaymentDetailsRes.java

@@ -54,6 +54,9 @@ public class WaitForPaymentDetailsRes extends ClientState {
 			if (paymentDetailsRes.getGenChallenge() == null) {
 				return new TerminateSession("GenChallenge not provided in PaymentDetailsRes");
 			} else {
+				// Save the sent genChallenge for the state WaitForAuthorizationRes if EVSEProcessing is set to ONGOING
+				getCommSessionContext().setSentGenChallenge(paymentDetailsRes.getGenChallenge());
+				
 				AuthorizationReqType authorizationReq = getAuthorizationReq(paymentDetailsRes.getGenChallenge());
 				
 				// Set xml reference element

+ 30 - 2
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/states/WaitForPreChargeRes.java

@@ -23,11 +23,16 @@
  *******************************************************************************/
 package org.v2gclarity.risev2g.evcc.states;
 
+import java.util.concurrent.TimeUnit;
+
+import org.v2gclarity.risev2g.evcc.evController.IDCEVController;
 import org.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
 import org.v2gclarity.risev2g.shared.enumerations.V2GMessages;
 import org.v2gclarity.risev2g.shared.messageHandling.ReactionToIncomingMessage;
 import org.v2gclarity.risev2g.shared.messageHandling.TerminateSession;
+import org.v2gclarity.risev2g.shared.misc.TimeRestrictions;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargeProgressType;
+import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PreChargeReqType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.PreChargeResType;
 import org.v2gclarity.risev2g.shared.v2gMessages.msgDef.V2GMessage;
 
@@ -44,9 +49,32 @@ public class WaitForPreChargeRes extends ClientState {
 			PreChargeResType preChargeRes = 
 					(PreChargeResType) v2gMessageRes.getBody().getBodyElement().getValue();
 			
-			// TODO how to react to DC_EVSEStatus and EVSEPresentVoltage?
+			// TODO how to react to DC_EVSEStatus
 			
-			return getSendMessage(getPowerDeliveryReq(ChargeProgressType.START), V2GMessages.POWER_DELIVERY_RES);
+			IDCEVController dcEvController = (IDCEVController) getCommSessionContext().getEvController();
+			double targetVoltage = dcEvController.getTargetVoltage().getValue() * Math.pow(10, dcEvController.getTargetVoltage().getMultiplier());
+			double presentVoltage = preChargeRes.getEVSEPresentVoltage().getValue() * Math.pow(10, preChargeRes.getEVSEPresentVoltage().getMultiplier());
+					
+			if (targetVoltage == presentVoltage) {
+				getCommSessionContext().setOngoingTimerActive(false);
+				getCommSessionContext().setOngoingTimer(0L);
+				
+				return getSendMessage(getPowerDeliveryReq(ChargeProgressType.START), V2GMessages.POWER_DELIVERY_RES);
+			} else {
+				long elapsedTime = System.nanoTime() - getCommSessionContext().getOngoingTimer();
+				long elapsedTimeInMs = TimeUnit.MILLISECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
+				
+				if (elapsedTimeInMs > TimeRestrictions.V2G_EVCC_PRE_CHARGE_TIMEOUT) 
+					return new TerminateSession("PreCharge timer timed out for PreChargeReq");
+				else {
+					PreChargeReqType preChargeReq = new PreChargeReqType();
+					preChargeReq.setDCEVStatus(dcEvController.getDCEVStatus());
+					preChargeReq.setEVTargetCurrent(dcEvController.getTargetCurrent());
+					preChargeReq.setEVTargetVoltage(dcEvController.getTargetVoltage());
+					
+					return getSendMessage(preChargeReq, V2GMessages.PRE_CHARGE_RES);
+				}
+			}
 		} else {
 			return new TerminateSession("Incoming message raised an error");
 		}

+ 1 - 0
RISE-V2G-EVCC/src/main/java/org/v2gclarity/risev2g/evcc/transportLayer/StatefulTransportLayerClient.java

@@ -58,6 +58,7 @@ public abstract class StatefulTransportLayerClient  extends Observable implement
 		setClientPort(MiscUtils.getRandomPortNumber());
 		setClientAddress(MiscUtils.getLinkLocalAddress());
 		setV2gTPHeader(new byte[8]);
+		setTimeout(2000); // Needed for the supportedAppProtocol timeout
 	}
 	
 	protected boolean processIncomingMessage() throws IOException {

+ 3 - 0
RISE-V2G-Shared/src/main/java/org/v2gclarity/risev2g/shared/misc/TimeRestrictions.java

@@ -38,6 +38,9 @@ public class TimeRestrictions {
 	private static Logger logger = LogManager.getLogger(TimeRestrictions.class.getSimpleName());
 	public static final int V2G_EVCC_SEQUENCE_PERFORMANCE_TIME = 40000;
 	public static final int V2G_SECC_SEQUENCE_TIMEOUT = 60000;
+	public static final int V2G_EVCC_ONGOING_TIMEOUT = 60000;
+	public static final int V2G_EVCC_CABLE_CHECK_TIMEOUT = 40000;
+	public static final int V2G_EVCC_PRE_CHARGE_TIMEOUT = 7000;
 	
 	/**
 	 * SDP client shall wait for SECC Discovery Response message for _at least_ 250 ms (see [V2G2-159])

+ 4 - 0
RISE-V2G-Shared/src/main/java/org/v2gclarity/risev2g/shared/utils/SecurityUtils.java

@@ -826,6 +826,8 @@ public final class SecurityUtils {
 			privateKey = (ECPrivateKey) keyStore.getKey(
 						alias, 
 						GlobalValues.PASSPHRASE_FOR_CERTIFICATES_AND_KEYS.toString().toCharArray());
+			
+			getLogger().debug("Private key used for creating signature: " + ByteUtils.toHexString(privateKey.getEncoded()));
 		} catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException e) {
 			getLogger().error("The private key from keystore with alias '" + alias + 
 							  "' could not be retrieved (" + e.getClass().getSimpleName() + ")", e);
@@ -981,6 +983,8 @@ public final class SecurityUtils {
 								 contractCert.getSubjectX500Principal().getName() + "' saved. " + 
 								 "Valid until " + contractCert.getNotAfter()
 								 ); 
+				getLogger().debug("Decrypted private key belonging to contract certificate saved. Key bytes: " + 
+								   ByteUtils.toHexString(contractCertPrivateKey.getEncoded()));
 			} else {
 				getLogger().error("Private key for contract certificate is not valid");
 				return false;