From 52b5e626785845e9cb44c516ade21a07b0aefac9 Mon Sep 17 00:00:00 2001
From: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Thu, 10 Oct 2013 08:13:44 +0300
Subject: [PATCH] Fixes issues with DTLS-SRTP.

---
 .../transform/dtls/DtlsControlImpl.java       |  41 +++
 .../transform/dtls/DtlsPacketTransformer.java | 245 +++++++++++++++---
 .../transform/dtls/TlsClientImpl.java         | 137 ++++++++++
 .../transform/dtls/TlsServerImpl.java         | 134 ++++++++++
 .../transform/srtp/SRTPCryptoContext.java     |   9 +-
 5 files changed, 528 insertions(+), 38 deletions(-)

diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java
index 85967ae6..f9d7768f 100644
--- a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java
+++ b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java
@@ -19,6 +19,7 @@
 import org.bouncycastle.crypto.*;
 import org.bouncycastle.crypto.generators.*;
 import org.bouncycastle.crypto.params.*;
+import org.bouncycastle.crypto.tls.*;
 import org.bouncycastle.crypto.util.*;
 import org.bouncycastle.operator.*;
 import org.bouncycastle.operator.bc.*;
@@ -57,6 +58,16 @@ public class DtlsControlImpl
      */
     private static final long ONE_DAY = 1000L * 60L * 60L * 24L;
 
+    /**
+     * The <tt>SRTPProtectionProfile</tt>s supported by
+     * <tt>DtlsControlImpl</tt>.
+     */
+    static final int[] SRTP_PROTECTION_PROFILES
+        = {
+            SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_80,
+            SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_32
+        };
+
     /**
      * The certificate with which the local endpoint represented by this
      * instance authenticates its ends of DTLS sessions. 
@@ -128,6 +139,36 @@ public DtlsControlImpl()
                     localFingerprintHashFunction);
     }
 
+    /**
+     * Chooses the first from a list of <tt>SRTPProtectionProfile</tt>s that is
+     * supported by <tt>DtlsControlImpl</tt>.
+     *
+     * @param theirs the list of <tt>SRTPProtectionProfile</tt>s to choose from
+     * @return the first from the specified <tt>theirs</tt> that is supported
+     * by <tt>DtlsControlImpl</tt>
+     */
+    static int chooseSRTPProtectionProfile(int... theirs)
+    {
+        int[] ours = SRTP_PROTECTION_PROFILES;
+
+        if (theirs != null)
+        {
+            for (int t = 0; t < theirs.length; t++)
+            {
+                int their = theirs[t];
+
+                for (int o = 0; o < ours.length; o++)
+                {
+                    int our = ours[o];
+
+                    if (their == our)
+                        return their;
+                }
+            }
+        }
+        return 0;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java
index 58290533..2b66d7e6 100644
--- a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java
+++ b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java
@@ -10,8 +10,10 @@
 import java.security.*;
 
 import org.bouncycastle.crypto.tls.*;
+import org.ice4j.ice.*;
 import org.jitsi.impl.neomedia.*;
 import org.jitsi.impl.neomedia.transform.*;
+import org.jitsi.impl.neomedia.transform.srtp.*;
 import org.jitsi.service.neomedia.*;
 import org.jitsi.util.*;
 
@@ -32,7 +34,7 @@ public class DtlsPacketTransformer
      * The number of milliseconds a <tt>DtlsPacketTransform</tt> is to wait on
      * its {@link #dtlsProtocol} in order to receive a packet.
      */
-    private static final int DTLS_TRANSPORT_RECEIVE_WAITMILLIS = 1;
+    private static final int DTLS_TRANSPORT_RECEIVE_WAITMILLIS = -1;
 
     /**
      * The <tt>Logger</tt> used by the <tt>DtlsPacketTransformer</tt> class and
@@ -142,6 +144,11 @@ public static boolean isDtlsRecord(byte[] buf, int off, int len)
      */
     private MediaType mediaType;
 
+    /**
+     * The <tt>SRTPTransformer</tt> to be used by this instance.
+     */
+    private PacketTransformer srtpTransformer;
+
     /**
      * The <tt>TransformEngine</tt> which has initialized this instance.
      */
@@ -222,6 +229,178 @@ DtlsTransformEngine getTransformEngine()
         return transformEngine;
     }
 
+    /**
+     * Initializes a new <tt>SRTPTransformer</tt> instance with a specific
+     * (negotiated) <tt>SRTPProtectionProfile</tt> and the keying material
+     * specified by a specific <tt>TlsContext</tt>.
+     *
+     * @param srtpProtectionProfile the (negotiated)
+     * <tt>SRTPProtectionProfile</tt> to initialize the new instance with
+     * @param tlsContext the <tt>TlsContext</tt> which represents the keying
+     * material
+     * @return a new <tt>SRTPTransformer</tt> instance initialized with
+     * <tt>srtpProtectionProfile</tt> and <tt>tlsContext</tt>
+     */
+    private PacketTransformer initializeSRTPTransformer(
+            int srtpProtectionProfile,
+            TlsContext tlsContext)
+    {
+        boolean rtcp;
+
+        switch (componentID)
+        {
+        case Component.RTCP:
+            rtcp = true;
+            break;
+        case Component.RTP:
+            rtcp = false;
+            break;
+        default:
+            throw new IllegalStateException("componentID");
+        }
+
+        int cipher_key_length;
+        int cipher_salt_length;
+        int cipher;
+        int auth_function;
+        int auth_key_length;
+        int RTCP_auth_tag_length, RTP_auth_tag_length;
+
+        switch (srtpProtectionProfile)
+        {
+        case SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_32:
+            cipher_key_length = 128 / 8;
+            cipher_salt_length = 112 / 8;
+            cipher = SRTPPolicy.AESCM_ENCRYPTION;
+            auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
+            auth_key_length = 160 / 8;
+            RTCP_auth_tag_length = 80 / 8;
+            RTP_auth_tag_length = 32 / 8;
+            break;
+        case SRTPProtectionProfile.SRTP_AES128_CM_HMAC_SHA1_80:
+            cipher_key_length = 128 / 8;
+            cipher_salt_length = 112 / 8;
+            cipher = SRTPPolicy.AESCM_ENCRYPTION;
+            auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
+            auth_key_length = 160 / 8;
+            RTCP_auth_tag_length = RTP_auth_tag_length = 80 / 8;
+            break;
+        case SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_32:
+            cipher_key_length = 0;
+            cipher_salt_length = 0;
+            cipher = SRTPPolicy.NULL_ENCRYPTION;
+            auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
+            auth_key_length = 160 / 8;
+            RTCP_auth_tag_length = 80 / 8;
+            RTP_auth_tag_length = 32 / 8;
+            break;
+        case SRTPProtectionProfile.SRTP_NULL_HMAC_SHA1_80:
+            cipher_key_length = 0;
+            cipher_salt_length = 0;
+            cipher = SRTPPolicy.NULL_ENCRYPTION;
+            auth_function = SRTPPolicy.HMACSHA1_AUTHENTICATION;
+            auth_key_length = 160 / 8;
+            RTCP_auth_tag_length = RTP_auth_tag_length = 80 / 8;
+            break;
+        default:
+            throw new IllegalArgumentException("srtpProtectionProfile");
+        }
+
+        byte[] keyingMaterial
+            = tlsContext.exportKeyingMaterial(
+                    ExporterLabel.dtls_srtp,
+                    null,
+                    2 * (cipher_key_length + cipher_salt_length));
+        byte[] client_write_SRTP_master_key = new byte[cipher_key_length];
+        byte[] server_write_SRTP_master_key = new byte[cipher_key_length];
+        byte[] client_write_SRTP_master_salt = new byte[cipher_salt_length];
+        byte[] server_write_SRTP_master_salt = new byte[cipher_salt_length];
+        byte[][] keyingMaterialValues
+            = {
+                client_write_SRTP_master_key,
+                server_write_SRTP_master_key,
+                client_write_SRTP_master_salt,
+                server_write_SRTP_master_salt
+            };
+
+        for (int i = 0, keyingMaterialOffset = 0;
+                i < keyingMaterialValues.length;
+                i++)
+        {
+            byte[] keyingMaterialValue = keyingMaterialValues[i];
+
+            System.arraycopy(
+                    keyingMaterial, keyingMaterialOffset,
+                    keyingMaterialValue, 0,
+                    keyingMaterialValue.length);
+            keyingMaterialOffset += keyingMaterialValue.length;
+        }
+
+        SRTPPolicy srtcpPolicy
+            = new SRTPPolicy(
+                    cipher,
+                    cipher_key_length,
+                    auth_function,
+                    auth_key_length,
+                    RTCP_auth_tag_length,
+                    cipher_salt_length);
+        SRTPPolicy srtpPolicy
+            = new SRTPPolicy(
+                    cipher,
+                    cipher_key_length,
+                    auth_function,
+                    auth_key_length,
+                    RTP_auth_tag_length,
+                    cipher_salt_length);
+        SRTPContextFactory clientSRTPContextFactory
+            = new SRTPContextFactory(
+                    client_write_SRTP_master_key,
+                    client_write_SRTP_master_salt,
+                    srtpPolicy,
+                    srtcpPolicy);
+        SRTPContextFactory serverSRTPContextFactory
+            = new SRTPContextFactory(
+                    server_write_SRTP_master_key,
+                    server_write_SRTP_master_salt,
+                    srtpPolicy,
+                    srtcpPolicy);
+        SRTPContextFactory forwardSRTPContextFactory;
+        SRTPContextFactory reverseSRTPContextFactory;
+
+        if (tlsContext instanceof TlsClientContext)
+        {
+            forwardSRTPContextFactory = clientSRTPContextFactory;
+            reverseSRTPContextFactory = serverSRTPContextFactory;
+        }
+        else if (tlsContext instanceof TlsServerContext)
+        {
+            forwardSRTPContextFactory = serverSRTPContextFactory;
+            reverseSRTPContextFactory = clientSRTPContextFactory;
+        }
+        else
+        {
+            throw new IllegalArgumentException("tlsContext");
+        }
+
+        PacketTransformer srtpTransformer;
+
+        if (rtcp)
+        {
+            srtpTransformer
+                = new SRTCPTransformer(
+                        forwardSRTPContextFactory,
+                        reverseSRTPContextFactory);
+        }
+        else
+        {
+            srtpTransformer
+                = new SRTPTransformer(
+                        forwardSRTPContextFactory,
+                        reverseSRTPContextFactory);
+        }
+        return srtpTransformer;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -297,6 +476,8 @@ else if (delta < 0)
                             delta = len - received;
                             if (delta > 0)
                                 pkt.shrink(delta);
+
+                            pkt = null;
                         }
                     }
                     catch (IOException ioe)
@@ -318,12 +499,12 @@ else if (delta < 0)
         }
         else
         {
-            /*
-             * The specified pkt does not look like a DTLS record so it is not a
-             * valid packet on the secure channel represented by this
-             * PacketTransformer.
-             */
-            pkt = null;
+            PacketTransformer srtpTransformer = this.srtpTransformer;
+
+            if (srtpTransformer == null)
+                pkt = null;
+            else
+                pkt = srtpTransformer.reverseTransform(pkt);
         }
         return pkt;
     }
@@ -341,12 +522,14 @@ private void runInConnectThread(
             DatagramTransport datagramTransport)
     {
         DTLSTransport dtlsTransport = null;
+        int srtpProtectionProfile;
+        TlsContext tlsContext;
 
         if (dtlsProtocol instanceof DTLSClientProtocol)
         {
             DTLSClientProtocol dtlsClientProtocol
                 = (DTLSClientProtocol) dtlsProtocol;
-            TlsClient tlsClient = (TlsClient) tlsPeer;
+            TlsClientImpl tlsClient = (TlsClientImpl) tlsPeer;
 
             try
             {
@@ -361,12 +544,14 @@ private void runInConnectThread(
                         "Failed to connect this DTLS client to a DTLS server!",
                         ioe);
             }
+            srtpProtectionProfile = tlsClient.getChosenProtectionProfile();
+            tlsContext = tlsClient.getContext();
         }
         else if (dtlsProtocol instanceof DTLSServerProtocol)
         {
             DTLSServerProtocol dtlsServerProtocol
                 = (DTLSServerProtocol) dtlsProtocol;
-            TlsServer tlsServer = (TlsServer) tlsPeer;
+            TlsServerImpl tlsServer = (TlsServerImpl) tlsPeer;
 
             try
             {
@@ -381,19 +566,30 @@ else if (dtlsProtocol instanceof DTLSServerProtocol)
                         "Failed to accept a connection from a DTLS client!",
                         ioe);
             }
+            srtpProtectionProfile = tlsServer.getChosenProtectionProfile();
+            tlsContext = tlsServer.getContext();
         }
         else
             throw new IllegalStateException("dtlsProtocol");
 
+        PacketTransformer srtpTransformer
+            = initializeSRTPTransformer(srtpProtectionProfile, tlsContext);
+        boolean closeSRTPTransformer;
+
         synchronized (this)
         {
             if (Thread.currentThread().equals(this.connectThread)
                     && datagramTransport.equals(this.datagramTransport))
             {
                 this.dtlsTransport = dtlsTransport;
+                this.srtpTransformer = srtpTransformer;
                 notifyAll();
             }
+            closeSRTPTransformer
+                = (this.srtpTransformer != srtpTransformer);
         }
+        if (closeSRTPTransformer)
+            srtpTransformer.close();
     }
 
     /**
@@ -577,6 +773,11 @@ private synchronized void stop()
             }
             dtlsTransport = null;
         }
+        if (srtpTransformer != null)
+        {
+            srtpTransformer.close();
+            srtpTransformer = null;
+        }
         closeDatagramTransport();
 
         notifyAll();
@@ -598,28 +799,12 @@ public RawPacket transform(RawPacket pkt)
          */
         if (!isDtlsRecord(buf, off, len))
         {
-            /*
-             * The specified pkt will pass through this PacketTransformer only
-             * if it gets transformed into a DTLS record.
-             */
-            pkt = null;
+            PacketTransformer srtpTransformer = this.srtpTransformer;
 
-            DTLSTransport dtlsTransport = this.dtlsTransport;
-
-            if (dtlsTransport != null)
-            {
-                try
-                {
-                    dtlsTransport.send(buf, off, len);
-                }
-                catch (IOException ioe)
-                {
-                    logger.error(
-                            "Failed to send application data over DTLS"
-                                + " transport!",
-                            ioe);
-                }
-            }
+            if (srtpTransformer == null)
+                pkt = null;
+            else
+                pkt = srtpTransformer.transform(pkt);
         }
         return pkt;
     }
diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java
index aa75730b..98c83e64 100644
--- a/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java
+++ b/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java
@@ -7,6 +7,7 @@
 package org.jitsi.impl.neomedia.transform.dtls;
 
 import java.io.*;
+import java.util.*;
 
 import org.bouncycastle.crypto.tls.*;
 import org.jitsi.util.*;
@@ -28,6 +29,20 @@ public class TlsClientImpl
     private final TlsAuthentication authentication
         = new TlsAuthenticationImpl();
 
+    /**
+     * The <tt>SRTPProtectionProfile</tt> negotiated between this DTLS-SRTP
+     * client and its server.
+     */
+    private int chosenProtectionProfile;
+
+    /**
+     * The SRTP Master Key Identifier (MKI) used by the
+     * <tt>SRTPCryptoContext</tt> associated with this instance. Since the
+     * <tt>SRTPCryptoContext</tt> class does not utilize it, the value is
+     * {@link TlsUtils#EMPTY_BYTES}.
+     */
+    private final byte[] mki = TlsUtils.EMPTY_BYTES;
+
     /**
      * The <tt>PacketTransformer</tt> which has initialized this instance.
      */
@@ -53,6 +68,44 @@ public synchronized TlsAuthentication getAuthentication()
         return authentication;
     }
 
+    /**
+     * Gets the <tt>SRTPProtectionProfile</tt> negotiated between this DTLS-SRTP
+     * client and its server.
+     *
+     * @return the <tt>SRTPProtectionProfile</tt> negotiated between this
+     * DTLS-SRTP client and its server
+     */
+    int getChosenProtectionProfile()
+    {
+        return chosenProtectionProfile;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Includes the <tt>use_srtp</tt> extension in the DTLS extended client
+     * hello.
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Hashtable getClientExtensions()
+        throws IOException
+    {
+        Hashtable clientExtensions = super.getClientExtensions();
+
+        if (TlsSRTPUtils.getUseSRTPExtension(clientExtensions) == null)
+        {
+            if (clientExtensions == null)
+                clientExtensions = new Hashtable();
+            TlsSRTPUtils.addUseSRTPExtension(
+                    clientExtensions,
+                    new UseSRTPData(
+                            DtlsControlImpl.SRTP_PROTECTION_PROFILES,
+                            mki));
+        }
+        return clientExtensions;
+    }
+
     /**
      * {@inheritDoc}
      *
@@ -67,6 +120,18 @@ public ProtocolVersion getClientVersion()
         return ProtocolVersion.DTLSv10;
     }
 
+    /**
+     * Gets the <tt>TlsContext</tt> with which this <tt>TlsClient</tt> has been
+     * initialized.
+     *
+     * @return the <tt>TlsContext</tt> with which this <tt>TlsClient</tt> has
+     * been initialized
+     */
+    TlsContext getContext()
+    {
+        return context;
+    }
+
     /**
      * Gets the <tt>DtlsControl</tt> implementation associated with this
      * instance.
@@ -88,6 +153,78 @@ public ProtocolVersion getMinimumVersion()
         return ProtocolVersion.DTLSv10;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * Overrides the super implementation as a simple means of detecting that
+     * the security-related negotiations between the local and the remote
+     * enpoints are starting. The detection carried out for the purposes of
+     * <tt>SrtpListener</tt>.
+     */
+    @Override
+    public void init(TlsClientContext context)
+    {
+        // TODO Auto-generated method stub
+        super.init(context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Makes sure that the DTLS extended server hello contains the
+     * <tt>use_srtp</tt> extension.
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public void processServerExtensions(Hashtable serverExtensions)
+        throws IOException
+    {
+        UseSRTPData useSRTPData
+            = TlsSRTPUtils.getUseSRTPExtension(serverExtensions);
+
+        if (useSRTPData == null)
+        {
+            throw new IOException(
+                    "DTLS extended server hello does not include the use_srtp"
+                        + " extension!");
+        }
+        else
+        {
+            int[] protectionProfiles = useSRTPData.getProtectionProfiles();
+            int chosenProtectionProfile
+                = (protectionProfiles.length == 1)
+                    ? DtlsControlImpl.chooseSRTPProtectionProfile(
+                            protectionProfiles[0])
+                    : 0;
+
+            if (chosenProtectionProfile == 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+            else
+            {
+                /*
+                 * If the client detects a nonzero-length MKI in the server's
+                 * response that is different than the one the client offered,
+                 * then the client MUST abort the handshake and SHOULD send an
+                 * invalid_parameter alert.
+                 */
+                byte[] mki = useSRTPData.getMki();
+
+                if (Arrays.equals(mki, this.mki))
+                {
+                    super.processServerExtensions(serverExtensions);
+
+                    this.chosenProtectionProfile = chosenProtectionProfile;
+                }
+                else
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+    }
+
     /**
      * Implements {@link TlsAuthentication} for the purposes of supporting
      * DTLS-SRTP.
diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/TlsServerImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/TlsServerImpl.java
index a12a41b9..e7d50ff9 100644
--- a/src/org/jitsi/impl/neomedia/transform/dtls/TlsServerImpl.java
+++ b/src/org/jitsi/impl/neomedia/transform/dtls/TlsServerImpl.java
@@ -7,6 +7,7 @@
 package org.jitsi.impl.neomedia.transform.dtls;
 
 import java.io.*;
+import java.util.*;
 
 import org.bouncycastle.crypto.tls.*;
 import org.jitsi.util.*;
@@ -30,6 +31,12 @@ public class TlsServerImpl
                 new short[] { ClientCertificateType.rsa_sign },
                 /* certificateAuthorities */ null);
 
+    /**
+     * The <tt>SRTPProtectionProfile</tt> negotiated between this DTLS-SRTP
+     * server and its client.
+     */
+    private int chosenProtectionProfile;
+
     /**
      * The <tt>PacketTransformer</tt> which has initialized this instance.
      */
@@ -57,6 +64,30 @@ public CertificateRequest getCertificateRequest()
         return certificateRequest;
     }
 
+    /**
+     * Gets the <tt>SRTPProtectionProfile</tt> negotiated between this DTLS-SRTP
+     * server and its client.
+     *
+     * @return the <tt>SRTPProtectionProfile</tt> negotiated between this
+     * DTLS-SRTP server and its client
+     */
+    int getChosenProtectionProfile()
+    {
+        return chosenProtectionProfile;
+    }
+
+    /**
+     * Gets the <tt>TlsContext</tt> with which this <tt>TlsServer</tt> has been
+     * initialized.
+     *
+     * @return the <tt>TlsContext</tt> with which this <tt>TlsServer</tt> has
+     * been initialized
+     */
+    TlsContext getContext()
+    {
+        return context;
+    }
+
     /**
      * Gets the <tt>DtlsControl</tt> implementation associated with this
      * instance.
@@ -112,6 +143,72 @@ protected TlsSignerCredentials getRSASignerCredentials()
         return rsaSignerCredentials;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * Includes the <tt>use_srtp</tt> extension in the DTLS extended server
+     * hello.
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Hashtable getServerExtensions()
+        throws IOException
+    {
+        Hashtable serverExtensions = super.getServerExtensions();
+
+        if (TlsSRTPUtils.getUseSRTPExtension(serverExtensions) == null)
+        {
+            if (serverExtensions == null)
+                serverExtensions = new Hashtable();
+
+            UseSRTPData useSRTPData
+                = TlsSRTPUtils.getUseSRTPExtension(clientExtensions);
+            int chosenProtectionProfile
+                = DtlsControlImpl.chooseSRTPProtectionProfile(
+                        useSRTPData.getProtectionProfiles());
+
+            /*
+             * If there is no shared profile and that is not acceptable, the
+             * server SHOULD return an appropriate DTLS alert.
+             */
+            if (chosenProtectionProfile == 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+            else
+            {
+                /*
+                 * Upon receipt of a "use_srtp" extension containing a
+                 * "srtp_mki" field, the server MUST include a matching
+                 * "srtp_mki" value in its "use_srtp" extension to indicate that
+                 * it will make use of the MKI.
+                 */
+                TlsSRTPUtils.addUseSRTPExtension(
+                        serverExtensions,
+                        new UseSRTPData(
+                                new int[] { chosenProtectionProfile },
+                                useSRTPData.getMki()));
+                this.chosenProtectionProfile = chosenProtectionProfile;
+            }
+        }
+        return serverExtensions;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Overrides the super implementation as a simple means of detecting that
+     * the security-related negotiations between the local and the remote
+     * enpoints are starting. The detection carried out for the purposes of
+     * <tt>SrtpListener</tt>.
+     */
+    @Override
+    public void init(TlsServerContext context)
+    {
+        // TODO Auto-generated method stub
+        super.init(context);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -134,4 +231,41 @@ public void notifyClientCertificate(Certificate clientCertificate)
                 throw new IOException(e);
         }
     }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Makes sure that the DTLS extended client hello contains the
+     * <tt>use_srtp</tt> extension.
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public void processClientExtensions(Hashtable clientExtensions)
+        throws IOException
+    {
+        UseSRTPData useSRTPData
+            = TlsSRTPUtils.getUseSRTPExtension(clientExtensions);
+
+        if (useSRTPData == null)
+        {
+            throw new IOException(
+                    "DTLS extended client hello does not include the use_srtp"
+                        + " extension!");
+        }
+        else
+        {
+            int chosenProtectionProfile
+                = DtlsControlImpl.chooseSRTPProtectionProfile(
+                        useSRTPData.getProtectionProfiles());
+
+            /*
+             * If there is no shared profile and that is not acceptable, the
+             * server SHOULD return an appropriate DTLS alert.
+             */
+            if (chosenProtectionProfile == 0)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            else
+                super.processClientExtensions(clientExtensions);
+        }
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/transform/srtp/SRTPCryptoContext.java b/src/org/jitsi/impl/neomedia/transform/srtp/SRTPCryptoContext.java
index c1f459ae..72f15b64 100644
--- a/src/org/jitsi/impl/neomedia/transform/srtp/SRTPCryptoContext.java
+++ b/src/org/jitsi/impl/neomedia/transform/srtp/SRTPCryptoContext.java
@@ -337,14 +337,7 @@ public int getAuthTagLength()
      */
     public int getMKILength()
     {
-        if (mki != null)
-        {
-            return mki.length;
-        }
-        else
-        {
-            return 0;
-        }
+        return (mki == null) ? 0 : mki.length;
     }
 
     /**
-- 
GitLab