From 74b747a0268ec9ba27783f3bebd9897089b5a898 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov <lyubomir.marinov@jitsi.org> Date: Thu, 20 Nov 2014 10:15:36 +0200 Subject: [PATCH] Adds a boolean ConfigurationService/System property org.jitsi.impl.neomedia.transform.dtls.DtlsPacketTransformer.dropUnencryptedPkts which indicates whether sent/received unencrypted packets are to be dropped. --- .../transform/dtls/DatagramTransportImpl.java | 5 + .../transform/dtls/DtlsControlImpl.java | 98 +++---- .../transform/dtls/DtlsPacketTransformer.java | 272 ++++++++++-------- .../transform/dtls/DtlsTransformEngine.java | 74 ++--- .../transform/dtls/TlsClientImpl.java | 3 + 5 files changed, 254 insertions(+), 198 deletions(-) diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DatagramTransportImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/DatagramTransportImpl.java index 502ba13b..71976ea2 100644 --- a/src/org/jitsi/impl/neomedia/transform/dtls/DatagramTransportImpl.java +++ b/src/org/jitsi/impl/neomedia/transform/dtls/DatagramTransportImpl.java @@ -151,6 +151,7 @@ private void breakOutOfDTLSReliableHandshakeReceiveMessage(Throwable cause) /** * {@inheritDoc} */ + @Override public void close() throws IOException { @@ -224,6 +225,7 @@ private void flush() /** * {@inheritDoc} */ + @Override public int getReceiveLimit() throws IOException { @@ -239,6 +241,7 @@ public int getReceiveLimit() /** * {@inheritDoc} */ + @Override public int getSendLimit() throws IOException { @@ -316,6 +319,7 @@ void queueReceive(byte[] buf, int off, int len) /** * {@inheritDoc} */ + @Override public int receive(byte[] buf, int off, int len, int waitMillis) throws IOException { @@ -453,6 +457,7 @@ public int receive(byte[] buf, int off, int len, int waitMillis) /** * {@inheritDoc} */ + @Override public void send(byte[] buf, int off, int len) throws IOException { diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java index c9cc03b4..2214e237 100644 --- a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java +++ b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsControlImpl.java @@ -405,11 +405,6 @@ private static String toHex(byte[] fingerprint) */ private final String localFingerprint; - /** - * Whether rtcp-mux is in use. - */ - private boolean rtcpmux = false; - /** * The hash function of {@link #localFingerprint} (which is the same as the * digest algorithm of the signature algorithm of {@link #certificate} in @@ -422,6 +417,11 @@ private static String toHex(byte[] fingerprint) */ private Map<String,String> remoteFingerprints; + /** + * Whether rtcp-mux is in use. + */ + private boolean rtcpmux = false; + /** * The value of the <tt>setup</tt> SDP attribute defined by RFC 4145 * "TCP-Based Media Transport in the Session Description Protocol @@ -474,22 +474,6 @@ public DtlsControlImpl(boolean disableSRTP) localFingerprintHashFunction); } - /** - * Prepares this <tt>DtlsControlImpl</tt> for garbage collection. - */ - private void doCleanup() - { - super.cleanup(null); - - setConnector(null); - - synchronized (this) - { - disposed = true; - notifyAll(); - } - } - /** * {@inheritDoc} */ @@ -521,6 +505,22 @@ protected DtlsTransformEngine createTransformEngine() return transformEngine; } + /** + * Prepares this <tt>DtlsControlImpl</tt> for garbage collection. + */ + private void doCleanup() + { + super.cleanup(null); + + setConnector(null); + + synchronized (this) + { + disposed = true; + notifyAll(); + } + } + /** * Gets the certificate with which the local endpoint represented by this * instance authenticates its ends of DTLS sessions. @@ -582,6 +582,18 @@ boolean isSrtpDisabled() return disableSRTP; } + /** + * {@inheritDoc} + */ + @Override + public void registerUser(Object user) + { + synchronized (users) + { + users.add(user); + } + } + /** * {@inheritDoc} * @@ -627,6 +639,22 @@ public void setRemoteFingerprints(Map<String,String> remoteFingerprints) } } + /** + * {@inheritDoc} + */ + @Override + public void setRtcpmux(boolean rtcpmux) + { + if (this.rtcpmux != rtcpmux) + { + this.rtcpmux = rtcpmux; + DtlsTransformEngine transformEngine = this.transformEngine; + + if (transformEngine != null) + transformEngine.setRtcpmux(rtcpmux); + } + } + /** * {@inheritDoc} */ @@ -789,32 +817,4 @@ boolean verifyAndValidateCertificate( } return b; } - - /** - * {@inheritDoc} - */ - public void setRtcpmux(boolean rtcpmux) - { - if (this.rtcpmux != rtcpmux) - { - this.rtcpmux = rtcpmux; - DtlsTransformEngine transformEngine = this.transformEngine; - - if (transformEngine != null) - transformEngine.setRtcpmux(rtcpmux); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void registerUser(Object user) - { - synchronized (users) - { - users.add(user); - } - } - } diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java index 9d7ab0c5..ed9cf9e2 100644 --- a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java +++ b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsPacketTransformer.java @@ -14,6 +14,8 @@ import org.jitsi.impl.neomedia.*; import org.jitsi.impl.neomedia.transform.*; import org.jitsi.impl.neomedia.transform.srtp.*; +import org.jitsi.service.configuration.*; +import org.jitsi.service.libjitsi.*; import org.jitsi.service.neomedia.*; import org.jitsi.util.*; @@ -26,6 +28,8 @@ public class DtlsPacketTransformer extends SinglePacketTransformer { + private static final long CONNECT_RETRY_INTERVAL = 500; + /** * The maximum number of times that * {@link #runInConnectThread(DTLSProtocol, TlsPeer, DatagramTransport)} is @@ -36,7 +40,23 @@ public class DtlsPacketTransformer */ private static final int CONNECT_TRIES = 3; - private static final long CONNECT_RETRY_INTERVAL = 500; + /** + * The indicator which determines whether unencrypted packets sent or + * received through <tt>DtlsPacketTransformer</tt> are to be dropped. The + * default value is <tt>false</tt>. + * + * @see #DROP_UNENCRYPTED_PKTS_PNAME + */ + private static final boolean DROP_UNENCRYPTED_PKTS; + + /** + * The name of the <tt>ConfigurationService</tt> and/or <tt>System</tt> + * property which indicates whether unencrypted packets sent or received + * through <tt>DtlsPacketTransformer</tt> are to be dropped. The default + * value is <tt>false</tt>. + */ + private static final String DROP_UNENCRYPTED_PKTS_PNAME + = DtlsPacketTransformer.class.getName() + ".dropUnencryptedPkts"; /** * The length of the header of a DTLS record. @@ -56,6 +76,28 @@ public class DtlsPacketTransformer private static final Logger logger = Logger.getLogger(DtlsPacketTransformer.class); + static + { + ConfigurationService cfg = LibJitsi.getConfigurationService(); + boolean dropUnencryptedPkts = false; + + if (cfg == null) + { + String s = System.getProperty(DROP_UNENCRYPTED_PKTS_PNAME); + + if (s != null) + dropUnencryptedPkts = Boolean.parseBoolean(s); + } + else + { + dropUnencryptedPkts + = cfg.getBoolean( + DROP_UNENCRYPTED_PKTS_PNAME, + dropUnencryptedPkts); + } + DROP_UNENCRYPTED_PKTS = dropUnencryptedPkts; + } + /** * Determines whether a specific array of <tt>byte</tt>s appears to contain * a DTLS record. @@ -123,14 +165,14 @@ public static boolean isDtlsRecord(byte[] buf, int off, int len) private final int componentID; /** - * The background <tt>Thread</tt> which initializes {@link #dtlsTransport}. + * The <tt>RTPConnector</tt> which uses this <tt>PacketTransformer</tt>. */ - private Thread connectThread; + private AbstractRTPConnector connector; /** - * The <tt>RTPConnector</tt> which uses this <tt>PacketTransformer</tt>. + * The background <tt>Thread</tt> which initializes {@link #dtlsTransport}. */ - private AbstractRTPConnector connector; + private Thread connectThread; /** * The <tt>DatagramTransport</tt> implementation which adapts @@ -152,9 +194,13 @@ public static boolean isDtlsRecord(byte[] buf, int off, int len) private MediaType mediaType; /** - * The <tt>SRTPTransformer</tt> to be used by this instance. + * Whether rtcp-mux is in use. + * + * If enabled, and this is the transformer for RTCP, it will not establish + * a DTLS session on its own, but rather wait for the RTP transformer to + * do so, and reuse it to initialize the SRTP transformer. */ - private SinglePacketTransformer srtpTransformer; + private boolean rtcpmux = false; /** * The value of the <tt>setup</tt> SDP attribute defined by RFC 4145 @@ -164,6 +210,11 @@ public static boolean isDtlsRecord(byte[] buf, int off, int len) */ private DtlsControl.Setup setup; + /** + * The <tt>SRTPTransformer</tt> to be used by this instance. + */ + private SinglePacketTransformer srtpTransformer; + /** * The indicator which determines whether the <tt>TlsPeer</tt> employed by * this <tt>PacketTransformer</tt> has raised an @@ -177,15 +228,6 @@ public static boolean isDtlsRecord(byte[] buf, int off, int len) */ private final DtlsTransformEngine transformEngine; - /** - * Whether rtcp-mux is in use. - * - * If enabled, and this is the transformer for RTCP, it will not establish - * a DTLS session on its own, but rather wait for the RTP transformer to - * do so, and reuse it to initialize the SRTP transformer. - */ - private boolean rtcpmux = false; - /** * Initializes a new <tt>DtlsPacketTransformer</tt> instance. * @@ -205,6 +247,7 @@ public DtlsPacketTransformer( /** * {@inheritDoc} */ + @Override public synchronized void close() { /* @@ -375,6 +418,41 @@ private boolean handleRunInConnectThreadException( return false; } + /** + * Tries to initialize {@link #srtpTransformer} by using the + * <tt>DtlsPacketTransformer</tt> for RTP. + * + * @return the (possibly updated) value of {@link #srtpTransformer}. + */ + private SinglePacketTransformer initializeSRTCPTransformerFromRtp() + { + if (srtpTransformer != null) + return srtpTransformer; //already initialized + + DtlsPacketTransformer rtpDtlsPacketTransformer + = (DtlsPacketTransformer) getTransformEngine().getRTPTransformer(); + + PacketTransformer rtpSrtpTransformer + = rtpDtlsPacketTransformer.srtpTransformer; + + if (rtpSrtpTransformer != null + && rtpSrtpTransformer instanceof SRTPTransformer) + { + synchronized (this) + { + if (srtpTransformer == null) //previous check was not synchronized + { + DtlsPacketTransformer.this.srtpTransformer + = new SRTCPTransformer( + (SRTPTransformer) rtpSrtpTransformer); + } + return srtpTransformer; + } + } + + return srtpTransformer; + } + /** * Initializes a new <tt>SRTPTransformer</tt> instance with a specific * (negotiated) <tt>SRTPProtectionProfile</tt> and the keying material @@ -579,6 +657,7 @@ void notifyAlertRaised( /** * {@inheritDoc} */ + @Override public RawPacket reverseTransform(RawPacket pkt) { byte[] buf = pkt.getBuffer(); @@ -590,8 +669,9 @@ public RawPacket reverseTransform(RawPacket pkt) if (rtcpmux && Component.RTCP == componentID) { // This should never happen. - logger.warn("Dropping a DTLS record, because it was received" - + " on the RTCP channel while rtcpmux is in use."); + logger.warn( + "Dropping a DTLS record, because it was received on the" + + " RTCP channel while rtcpmux is in use."); return null; } @@ -693,9 +773,7 @@ else if (delta < 0) } else if (transformEngine.isSrtpDisabled()) { - /** - * In pure DTLS mode only DTLS records pass through. - */ + // In pure DTLS mode only DTLS records pass through. pkt = null; } else @@ -717,6 +795,8 @@ else if (transformEngine.isSrtpDisabled()) if (srtpTransformer != null) pkt = srtpTransformer.reverseTransform(pkt); + else if (DROP_UNENCRYPTED_PKTS) + pkt = null; } return pkt; } @@ -841,6 +921,53 @@ else if (dtlsProtocol instanceof DTLSServerProtocol) srtpTransformer.close(); } + /** + * Sends the data contained in a specific byte array as application data + * through the DTLS connection of this <tt>DtlsPacketTransformer</tt>. + * + * @param buf the byte array containing data to send. + * @param off the offset in <tt>buf</tt> where the data begins. + * @param len the length of data to send. + */ + public void sendApplicationData(byte[] buf, int off, int len) + { + DTLSTransport dtlsTransport = this.dtlsTransport; + Exception exception = null; + + if (dtlsTransport != null) + { + try + { + dtlsTransport.send(buf, off, len); + } + catch (IOException ioe) + { + exception = ioe; + } + } + else + { + exception = new NullPointerException("dtlsTransport"); + } + + if (exception != null) + { + /* + * SrtpControl.start(MediaType) starts its associated + * TransformEngine. We will use that mediaType to signal the + * normal stop then as well i.e. we will ignore exception + * after the procedure to stop this PacketTransformer has + * begun. + */ + if ((mediaType != null) && !tlsPeerHasRaisedCloseNotifyWarning) + { + logger.error( + "Failed to send application data over DTLS transport: ", + exception); + } + } + } + /** * Sets the <tt>RTPConnector</tt> which is to use or uses this * <tt>PacketTransformer</tt>. @@ -883,6 +1010,15 @@ synchronized void setMediaType(MediaType mediaType) } } + /** + * Enables/disables rtcp-mux. + * @param rtcpmux whether to enable or disable. + */ + void setRtcpmux(boolean rtcpmux) + { + this.rtcpmux = rtcpmux; + } + /** * Sets the DTLS protocol according to which this * <tt>DtlsPacketTransformer</tt> is to act either as a DTLS server or a @@ -1054,6 +1190,7 @@ private synchronized void stop() /** * {@inheritDoc} */ + @Override public RawPacket transform(RawPacket pkt) { byte[] buf = pkt.getBuffer(); @@ -1088,6 +1225,8 @@ public RawPacket transform(RawPacket pkt) if (srtpTransformer != null) pkt = srtpTransformer.transform(pkt); + else if (DROP_UNENCRYPTED_PKTS) + pkt = null; } /* Pure DTLS mode */ else @@ -1128,95 +1267,4 @@ public RawPacket transform(RawPacket pkt) } return pkt; } - - /** - * Sends the data contained in a specific byte array as application data - * through the DTLS connection of this <tt>DtlsPacketTransformer</tt>. - * - * @param buf the byte array containing data to send. - * @param off the offset in <tt>buf</tt> where the data begins. - * @param len the length of data to send. - */ - public void sendApplicationData(byte[] buf, int off, int len) - { - DTLSTransport dtlsTransport = this.dtlsTransport; - Exception exception = null; - - if (dtlsTransport != null) - { - try - { - dtlsTransport.send(buf, off, len); - } - catch (IOException ioe) - { - exception = ioe; - } - } - else - { - exception = new NullPointerException("dtlsTransport"); - } - - if (exception != null) - { - /* - * SrtpControl.start(MediaType) starts its associated - * TransformEngine. We will use that mediaType to signal the - * normal stop then as well i.e. we will ignore exception - * after the procedure to stop this PacketTransformer has - * begun. - */ - if ((mediaType != null) && !tlsPeerHasRaisedCloseNotifyWarning) - { - logger.error( - "Failed to send application data over DTLS transport: ", - exception); - } - } - } - - /** - * Enables/disables rtcp-mux. - * @param rtcpmux whether to enable or disable. - */ - void setRtcpmux(boolean rtcpmux) - { - this.rtcpmux = rtcpmux; - } - - /** - * Tries to initialize {@link #srtpTransformer} by using the - * <tt>DtlsPacketTransformer</tt> for RTP. - * - * @return the (possibly updated) value of {@link #srtpTransformer}. - */ - private SinglePacketTransformer initializeSRTCPTransformerFromRtp() - { - if (srtpTransformer != null) - return srtpTransformer; //already initialized - - DtlsPacketTransformer rtpDtlsPacketTransformer - = (DtlsPacketTransformer) getTransformEngine().getRTPTransformer(); - - PacketTransformer rtpSrtpTransformer - = rtpDtlsPacketTransformer.srtpTransformer; - - if (rtpSrtpTransformer != null - && rtpSrtpTransformer instanceof SRTPTransformer) - { - synchronized (this) - { - if (srtpTransformer == null) //previous check was not synchronized - { - DtlsPacketTransformer.this.srtpTransformer - = new SRTCPTransformer( - (SRTPTransformer) rtpSrtpTransformer); - } - return srtpTransformer; - } - } - - return srtpTransformer; - } } diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsTransformEngine.java b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsTransformEngine.java index bf4af747..094c51ad 100644 --- a/src/org/jitsi/impl/neomedia/transform/dtls/DtlsTransformEngine.java +++ b/src/org/jitsi/impl/neomedia/transform/dtls/DtlsTransformEngine.java @@ -32,15 +32,6 @@ public class DtlsTransformEngine */ private boolean disposed = false; - /** - * Whether rtcp-mux is in use. - * - * When enabled, the <tt>DtlsPacketTransformer</tt> will, instead of - * establishing a DTLS session, wait for the transformer for RTP to - * establish one, and reuse it to initialize its SRTP transformer. - */ - private boolean rtcpmux = false; - /** * The <tt>DtlsControl</tt> which has initialized this instance. */ @@ -59,6 +50,15 @@ public class DtlsTransformEngine private final DtlsPacketTransformer[] packetTransformers = new DtlsPacketTransformer[2]; + /** + * Whether rtcp-mux is in use. + * + * When enabled, the <tt>DtlsPacketTransformer</tt> will, instead of + * establishing a DTLS session, wait for the transformer for RTP to + * establish one, and reuse it to initialize its SRTP transformer. + */ + private boolean rtcpmux = false; + /** * The value of the <tt>setup</tt> SDP attribute defined by RFC 4145 * "TCP-Based Media Transport in the Session Description Protocol @@ -174,6 +174,16 @@ public PacketTransformer getRTPTransformer() return getPacketTransformer(Component.RTP); } + /** + * Indicates if SRTP extensions should be disabled which means we are + * currently working in pure DTLS mode. + * @return <tt>true</tt> if SRTP extensions should be disabled. + */ + boolean isSrtpDisabled() + { + return dtlsControl.isSrtpDisabled(); + } + /** * Sets the <tt>RTPConnector</tt> which is to use or uses this * <tt>TransformEngine</tt>. @@ -216,6 +226,24 @@ private void setMediaType(MediaType mediaType) } } + /** + * Enables/disables rtcp-mux. + * @param rtcpmux whether to enable or disable. + */ + void setRtcpmux(boolean rtcpmux) + { + if (this.rtcpmux != rtcpmux) + { + this.rtcpmux = rtcpmux; + + for (DtlsPacketTransformer packetTransformer : packetTransformers) + { + if (packetTransformer != null) + packetTransformer.setRtcpmux(rtcpmux); + } + } + } + /** * Sets the DTLS protocol according to which this * <tt>DtlsTransformEngine</tt> is to act either as a DTLS server or a DTLS @@ -249,32 +277,4 @@ void start(MediaType mediaType) { setMediaType(mediaType); } - - /** - * Indicates if SRTP extensions should be disabled which means we are - * currently working in pure DTLS mode. - * @return <tt>true</tt> if SRTP extensions should be disabled. - */ - boolean isSrtpDisabled() - { - return dtlsControl.isSrtpDisabled(); - } - - /** - * Enables/disables rtcp-mux. - * @param rtcpmux whether to enable or disable. - */ - void setRtcpmux(boolean rtcpmux) - { - if (this.rtcpmux != rtcpmux) - { - this.rtcpmux = rtcpmux; - - for (DtlsPacketTransformer packetTransformer : packetTransformers) - { - if (packetTransformer != null) - packetTransformer.setRtcpmux(rtcpmux); - } - } - } } diff --git a/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java b/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java index e03e4a90..ace9a33d 100644 --- a/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java +++ b/src/org/jitsi/impl/neomedia/transform/dtls/TlsClientImpl.java @@ -62,6 +62,7 @@ public TlsClientImpl(DtlsPacketTransformer packetTransformer) /** * {@inheritDoc} */ + @Override public synchronized TlsAuthentication getAuthentication() throws IOException { @@ -303,6 +304,7 @@ private class TlsAuthenticationImpl /** * {@inheritDoc} */ + @Override public TlsCredentials getClientCredentials( CertificateRequest certificateRequest) throws IOException @@ -330,6 +332,7 @@ public TlsCredentials getClientCredentials( /** * {@inheritDoc} */ + @Override public void notifyServerCertificate(Certificate serverCertificate) throws IOException { -- GitLab