/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jitsi.impl.neomedia; import gnu.java.zrtp.*; import gnu.java.zrtp.utils.*; import java.util.*; import org.jitsi.impl.neomedia.transform.zrtp.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.event.*; /** * Controls zrtp in the MediaStream. * * @author Damian Minkov */ public class ZrtpControlImpl implements ZrtpControl { /** * The listener interested in security events about zrtp. */ private SrtpListener zrtpListener = null; /** * Additional info codes for and data to support ZRTP4J. * These could be added to the library. However they are specific for this * implementation, needing them for various GUI changes. */ public static enum ZRTPCustomInfoCodes { ZRTPNotEnabledByUser, ZRTPDisabledByCallEnd, ZRTPEngineInitFailure, ZRTPEnabledByDefault } /** * The zrtp engine control by this ZrtpControl. */ private ZRTPTransformEngine zrtpEngine = null; /** * This is the connector, required to send ZRTP packets * via the DatagramSocket. */ private AbstractRTPConnector zrtpConnector = null; /** * Whether current is master session. */ private boolean masterSession = false; /** * Creates the control. */ ZrtpControlImpl() { } /** * Cleans up the current zrtp control and its engine. */ public void cleanup() { if(zrtpEngine != null) { zrtpEngine.stopZrtp(); zrtpEngine.cleanup(); } zrtpEngine = null; zrtpConnector = null; } /** * Sets a <tt>ZrtpListener</tt> that will listen for zrtp security events. * * @param zrtpListener the <tt>ZrtpListener</tt> to set */ public void setSrtpListener(SrtpListener zrtpListener) { this.zrtpListener = zrtpListener; } /** * Returns the <tt>ZrtpListener</tt> which listens for security events. * * @return the <tt>ZrtpListener</tt> which listens for security events */ public SrtpListener getSrtpListener() { return this.zrtpListener; } /** * Method for getting the default secure status value for communication * * @return the default enabled/disabled status value for secure * communication */ public boolean getSecureCommunicationStatus() { return (zrtpEngine != null) && zrtpEngine.getSecureCommunicationStatus(); } /** * Sets the SAS verification * * @param verified the new SAS verification status */ public void setSASVerification(boolean verified) { ZRTPTransformEngine engine = getTransformEngine(); if (verified) engine.SASVerified(); else engine.resetSASVerified(); } /** * Returns the zrtp engine currently used by this stream. * @return the zrtp engine */ public ZRTPTransformEngine getTransformEngine() { if(zrtpEngine == null) { zrtpEngine = new ZRTPTransformEngine(); // NOTE: set paranoid mode before initializing // zrtpEngine.setParanoidMode(paranoidMode); zrtpEngine.initialize( "GNUZRTP4J.zid", false, ZrtpConfigureUtils.getZrtpConfiguration()); zrtpEngine.setUserCallback(new SecurityEventManager(this)); } return zrtpEngine; } /** * When in multistream mode, enables the master session. * @param masterSession whether current control, controls the master session. */ public void setMasterSession(boolean masterSession) { // by default its not master, change only if set to be master // sometimes (jingle) streams are re-initing and // we must reuse old value (true) event that false is submitted if(masterSession) this.masterSession = masterSession; } /** * Starts and enables zrtp in the stream holding this control. * @param mediaType the media type of the stream this control controls. */ public void start(MediaType mediaType) { boolean zrtpAutoStart; // ZRTP engine initialization ZRTPTransformEngine engine = getTransformEngine(); // Create security user callback for each peer. SecurityEventManager securityEventManager = engine.getUserCallback(); // Decide if this will become the ZRTP Master session: // - Statement: audio media session will be started before video // media session // - if no other audio session was started before then this will // become // ZRTP Master session // - only the ZRTP master sessions start in "auto-sensing" mode // to immediately catch ZRTP communication from other client // - after the master session has completed its key negotiation // it will start other media sessions (see SCCallback) if (masterSession) { zrtpAutoStart = true; securityEventManager.setDHSession(true); // we know that audio is considered as master for zrtp securityEventManager.setSessionType( mediaType.equals(MediaType.AUDIO) ? SecurityEventManager.AUDIO_SESSION : SecurityEventManager.VIDEO_SESSION ); } else { // check whether video was not already started // it may happen when using multistreams, audio has inited // and started video // initially engine has value enableZrtp = false zrtpAutoStart = zrtpEngine.isEnableZrtp(); securityEventManager.setSessionType( mediaType.equals(MediaType.AUDIO) ? SecurityEventManager.AUDIO_SESSION : SecurityEventManager.VIDEO_SESSION); } engine.setConnector(zrtpConnector); securityEventManager.setSrtpListener(zrtpListener); // tells the engine whether to autostart(enable) // zrtp communication, if false it just passes packets without // transformation engine.setEnableZrtp(zrtpAutoStart); engine.sendInfo( ZrtpCodes.MessageSeverity.Info, EnumSet.of( ZRTPCustomInfoCodes.ZRTPEnabledByDefault)); } /** * Start multi-stream ZRTP sessions. * * After the ZRTP Master (DH) session reached secure state the SCCallback * calls this method to start the multi-stream ZRTP sessions. * * enable auto-start mode (auto-sensing) to the engine. * @param master master SRTP data */ public void setMultistream(SrtpControl master) { if(master == null || master == this) return; if(!(master instanceof ZrtpControlImpl)) throw new IllegalArgumentException("master is no ZRTP control"); ZRTPTransformEngine engine = getTransformEngine(); engine.setMultiStrParams(((ZrtpControlImpl) master) .getTransformEngine().getMultiStrParams()); engine.setEnableZrtp(true); } /** * Return the zrtp hello hash String. * * @return String the zrtp hello hash. */ public String getHelloHash() { return getTransformEngine().getHelloHash(); } /** * Get the ZRTP Hello Hash data - separate strings. * * @return String array containing the version string at offset 0, the Hello * hash value as hex-digits at offset 1. Hello hash is available * immediately after class instantiation. Returns <code>null</code> * if ZRTP is not available. */ public String[] getHelloHashSep() { return getTransformEngine().getHelloHashSep(); } /** * Sets the <tt>RTPConnector</tt> which is to use or uses this ZRTP engine. * * @param connector the <tt>RTPConnector</tt> which is to use or uses this * ZRTP engine */ public void setConnector(AbstractRTPConnector connector) { zrtpConnector = connector; } /* * (non-Javadoc) * * @see * net.java.sip.communicator.service.neomedia.ZrtpControl#getSecurityString * () */ public String getSecurityString() { return getTransformEngine().getUserCallback().getSecurityString(); } /* * (non-Javadoc) * * @see * net.java.sip.communicator.service.neomedia.ZrtpControl#getCiperString * () */ public String getCipherString() { return getTransformEngine().getUserCallback().getCipherString(); } /* * (non-Javadoc) * * @see * net.java.sip.communicator.service.neomedia.ZrtpControl#isSecurityVerified * () */ public boolean isSecurityVerified() { return getTransformEngine().getUserCallback().isSecurityVerified(); } /* * (non-Javadoc) * * @see * net.java.sip.communicator.service.neomedia.ZrtpControl#getPeerZid * () */ public byte[] getPeerZid() { return getTransformEngine().getPeerZid(); } /* * (non-Javadoc) * * @see * net.java.sip.communicator.service.neomedia.ZrtpControl#getPeerZidString * () */ public String getPeerZidString() { byte[] zid = getPeerZid(); String s = new String(ZrtpUtils.bytesToHexString(zid, zid.length)); return s; } /** * Returns false, ZRTP exchanges is keys over the media path. * * @return false */ public boolean requiresSecureSignalingTransport() { return false; } /** * Returns the timeout value that will we will wait * and fire timeout secure event if call is not secured. * The value is in milliseconds. * @return the timeout value that will we will wait * and fire timeout secure event if call is not secured. */ public long getTimeoutValue() { // this is the default value as mentioned in rfc6189 // we will later grab this setting from zrtp return 3750; } }