[ice4j] r154 committed - Splits candidate check handler into a client and a server. Delays nece...

ice4j at googlecode.com ice4j at googlecode.com
Wed Apr 28 01:32:27 CEST 2010


Revision: 154
Author: emcho at sip-communicator.org
Date: Tue Apr 27 16:31:58 2010
Log: Splits candidate check handler into a client and a server. Delays  
necessity of a password for outgoing checks so that we could handle the  
OFFER check ANSWER case.
http://code.google.com/p/ice4j/source/detail?r=154

Added:
  /trunk/src/org/ice4j/ice/ConnectivityCheckClient.java
Deleted:
  /trunk/src/org/ice4j/ice/ConnectivityCheckHandler.java
Modified:
  /trunk/src/org/ice4j/attribute/AttributeFactory.java
  /trunk/src/org/ice4j/attribute/MessageIntegrityAttribute.java
  /trunk/src/org/ice4j/ice/Agent.java
  /trunk/src/org/ice4j/ice/ConnectivityCheckServer.java
  /trunk/src/org/ice4j/message/Message.java
  /trunk/src/org/ice4j/security/CredentialsAuthority.java
  /trunk/src/org/ice4j/security/CredentialsManager.java
  /trunk/src/org/ice4j/stack/NetAccessManager.java

=======================================
--- /dev/null
+++ /trunk/src/org/ice4j/ice/ConnectivityCheckClient.java	Tue Apr 27  
16:31:58 2010
@@ -0,0 +1,142 @@
+/*
+ * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal.
+ * Maintained by the SIP Communicator community  
(http://sip-communicator.org).
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package org.ice4j.ice;
+
+import java.net.*;
+import java.util.logging.*;
+
+import org.ice4j.*;
+import org.ice4j.attribute.*;
+import org.ice4j.message.*;
+import org.ice4j.stack.*;
+
+/**
+ * @author Emil Ivov
+ */
+public class ConnectivityCheckClient
+    implements ResponseCollector
+{
+    /**
+     * The <tt>Logger</tt> used by the <tt>ConnectivityCheckClient</tt>
+     * class and its instances for logging output.
+     */
+    private static final Logger logger = Logger
+                    .getLogger(ConnectivityCheckClient.class.getName());
+
+    /**
+     * The agent that created us.
+     */
+    private final Agent parentAgent;
+
+    /**
+     * The stun stack that we will use for connectivity checks.
+     */
+    StunStack stunStack = StunStack.getInstance();
+
+    /**
+     * Creates a new <tt>ConnectivityCheckHandler</tt> setting
+     * <tt>parentAgent</tt> as the agent that will be used for retrieving
+     * information such as user fragments for example.
+     *
+     * @param parentAgent the <tt>Agent</tt> that is creating this  
instance.
+     */
+    public ConnectivityCheckClient(Agent parentAgent)
+    {
+        this.parentAgent = parentAgent;
+    }
+
+    public void startChecks(CheckList checkList)
+    {
+        for(CandidatePair pair : checkList)
+        {
+            startCheckForPair(pair);
+        }
+    }
+
+
+    private void startCheckForPair(CandidatePair pair)
+    {
+        //we don't need to do a canReach() verification here as it has been
+        //already verified during the gathering process.
+        DatagramSocket stunSocket =  
((HostCandidate)pair.getLocalCandidate())
+            .getStunSocket(null);
+
+        Request request = MessageFactory.createBindingRequest();
+
+        //priority
+        PriorityAttribute priority =  
AttributeFactory.createPriorityAttribute(
+            pair.getLocalCandidate().computePriorityForType(
+                            CandidateType.PEER_REFLEXIVE_CANDIDATE));
+
+        request.addAttribute(priority);
+
+        //controlling controlled
+        if (parentAgent.isControlling())
+        {
+            request.addAttribute(AttributeFactory
+                            .createIceControllingAttribute(parentAgent
+                                            .getTieBreaker()));
+        }
+        else
+        {
+            request.addAttribute(AttributeFactory
+                            .createIceControlledAttribute(parentAgent
+                                            .getTieBreaker()));
+        }
+
+        //credentials
+        UsernameAttribute unameAttr =  
AttributeFactory.createUsernameAttribute(
+                        parentAgent.generateLocalUserName());
+
+        request.addAttribute(unameAttr);
+
+        //todo: do this in the stun stack so that we could do the
+        //calculation once the request is ready (we'd need the transaction  
id
+        //for example.
+        //todo: also implement SASL prepare
+        MessageIntegrityAttribute msgIntegrity = AttributeFactory
+            .createMessageIntegrityAttribute(parentAgent
+                            .generateRemoteUserName());
+
+
+        request.addAttribute(msgIntegrity);
+
+        TransactionID tran;
+
+        try
+        {
+            tran = stunStack.sendRequest(request,
+                    pair.getRemoteCandidate().getTransportAddress(),  
stunSocket,
+                    this);
+System.out.println("checking pair " + pair + " with tran=" +  
tran.toString());
+        }
+        catch (Exception exception)
+        {
+            logger.log( Level.INFO,
+                        "Failed to send " + request + " through "
+                        + stunSocket.getLocalSocketAddress(),
+                        exception);
+            return;
+        }
+    }
+
+    public void processResponse(StunMessageEvent response)
+    {
+    }
+
+    public void processTimeout(StunTimeoutEvent event)
+    {
+        System.out.println("timeout event=" + event);
+    }
+
+    public void processUnreachable(StunFailureEvent event)
+    {
+        System.out.println("failure event=" + event);
+    }
+
+
+}
=======================================
--- /trunk/src/org/ice4j/ice/ConnectivityCheckHandler.java	Mon Apr 26  
14:33:21 2010
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal.
- * Maintained by the SIP Communicator community  
(http://sip-communicator.org).
- *
- * Distributable under LGPL license. See terms of license at gnu.org.
- */
-package org.ice4j.ice;
-
-import java.io.*;
-import java.net.*;
-import java.util.logging.*;
-
-import org.ice4j.*;
-import org.ice4j.attribute.*;
-import org.ice4j.message.*;
-import org.ice4j.security.*;
-import org.ice4j.socket.*;
-import org.ice4j.stack.*;
-
-/**
- * @author Emil Ivov
- */
-public class ConnectivityCheckHandler
-    implements ResponseCollector,
-               RequestListener,
-               CredentialsAuthority
-{
-    /**
-     * The <tt>Logger</tt> used by the <tt>ConnectivityCheckClient</tt>
-     * class and its instances for logging output.
-     */
-    private static final Logger logger = Logger
-                    .getLogger(ConnectivityCheckHandler.class.getName());
-
-    /**
-     * The agent that created us.
-     */
-    private final Agent parentAgent;
-
-    /**
-     * The stun stack that we will use for connectivity checks.
-     */
-    StunStack stunStack = StunStack.getInstance();
-
-    /**
-     * The <tt>DatagramPacketFilter</tt> that only accepts STUN messages.
-     */
-    private DatagramPacketFilter stunDatagramPacketFilter;
-
-    /**
-     * Creates a new <tt>ConnectivityCheckHandler</tt> setting
-     * <tt>parentAgent</tt> as the agent that will be used for retrieving
-     * information such as user fragments for example.
-     *
-     * @param parentAgent the <tt>Agent</tt> that is creating this  
instance.
-     */
-    public ConnectivityCheckHandler(Agent parentAgent)
-    {
-        this.parentAgent = parentAgent;
-        stunStack.addRequestListener(this);
-        stunStack.getCredentialsManager().registerAuthority(this);
-    }
-
-    public void startChecks(CheckList checkList)
-    {
-        for(CandidatePair pair : checkList)
-        {
-            startCheckForPair(pair);
-        }
-    }
-
-
-    private void startCheckForPair(CandidatePair pair)
-    {
-        //we don't need to do a canReach() verification here as it has been
-        //already verified during the gathering process.
-        DatagramSocket stunSocket =  
((HostCandidate)pair.getLocalCandidate())
-            .getStunSocket(null);
-
-        Request request = MessageFactory.createBindingRequest();
-
-        //priority
-        PriorityAttribute priority =  
AttributeFactory.createPriorityAttribute(
-            pair.getLocalCandidate().computePriorityForType(
-                            CandidateType.PEER_REFLEXIVE_CANDIDATE));
-
-        request.addAttribute(priority);
-
-        //controlling controlled
-        if (parentAgent.isControlling())
-        {
-            request.addAttribute(AttributeFactory
-                            .createIceControllingAttribute(parentAgent
-                                            .getTieBreaker()));
-        }
-        else
-        {
-            request.addAttribute(AttributeFactory
-                            .createIceControlledAttribute(parentAgent
-                                            .getTieBreaker()));
-        }
-
-        //credentials
-        UsernameAttribute unameAttr =  
AttributeFactory.createUsernameAttribute(
-                        parentAgent.generateLocalUserName());
-
-        request.addAttribute(unameAttr);
-
-        //todo: do this in the stun stack so that we could do the
-        //calculation once the request is ready (we'd need the transaction  
id
-        //for example.
-        //todo: also implement SASL prepare
-        MessageIntegrityAttribute msgIntegrity
-            = AttributeFactory.createMessageIntegrityAttribute(
-                            parentAgent.getRemotePassword().getBytes());
-
-
-        request.addAttribute(msgIntegrity);
-
-        TransactionID tran;
-
-        try
-        {
-            tran = stunStack.sendRequest(request,
-                    pair.getRemoteCandidate().getTransportAddress(),  
stunSocket,
-                    this);
-System.out.println("checking pair " + pair + " with tran=" +  
tran.toString());
-        }
-        catch (Exception exception)
-        {
-            logger.log( Level.INFO,
-                        "Failed to send " + request + " through "
-                        + stunSocket.getLocalSocketAddress(),
-                        exception);
-            return;
-        }
-    }
-
-    public void processResponse(StunMessageEvent response)
-    {
-    }
-
-    public void processTimeout(StunTimeoutEvent event)
-    {
-        System.out.println("timeout event=" + event);
-    }
-
-    public void processUnreachable(StunFailureEvent event)
-    {
-        System.out.println("failure event=" + event);
-    }
-
-    public void requestReceived(StunMessageEvent evt)
-    {
-        Request request = (Request)evt.getMessage();
-
-        //check the user name
-        if(! checkUserName(request))
-            return;
-
-        //check message integrity.
-
-        Response response = MessageFactory.createBindingResponse(
-                        request, evt.getRemoteAddress());
-        try
-        {
-             
stunStack.sendResponse(evt.getTransactionID().getTransactionID(),
-                response, evt.getLocalAddress(), evt.getRemoteAddress());
-        }
-        catch (Exception e)
-        {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Verifies whether <tt>request</tt> comes with the proper username and
-     * returns <tt>true</tt> if it does and <tt>false</tt> otherwise.
-     *
-     * @param request the <tt>Request</tt> that we'd like to check for a
-     * proper username.
-     *
-     * @return <tt>true</tt> if the <tt>request</tt> contains the proper  
user
-     * name and false otherwise.
-     */
-    public boolean checkUserName(Request request)
-    {
-        UsernameAttribute unameAttr
-            = (UsernameAttribute)request.getAttribute(Attribute.USERNAME);
-
-        if (unameAttr == null)
-        {
-            if(logger.isLoggable(Level.FINE))
-            {
-                logger.log(Level.FINE, "Received a request without a  
USERNAME");
-            }
-            return false;
-        }
-
-        String username = new String(unameAttr.getUsername());
-        int colon = username.indexOf(":");
-        if( username.length() < 1
-            || colon < 1)
-        {
-            if(logger.isLoggable(Level.FINE))
-            {
-                logger.log(Level.FINE, "Received a request with an  
improperly "
-                            +"formatted username");
-            }
-            return false;
-        }
-
-        String lfrag = username.substring(0, colon);
-
-        if( !lfrag.equals(parentAgent.getLocalUfrag()))
-        {
-            if(logger.isLoggable(Level.FINE))
-            {
-                logger.log(Level.FINE, "Remote peer using a wrong user  
name: "
-                                       + username);
-            }
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Implements the {@link CredentialsAuthority#getKey(String)} method  
in a
-     * way that would return this handler's parent agent password if
-     * <tt>username</tt> is either the local ufrag or the username that the
-     * agent's remote peer was expected to use.
-     *
-     * @param username the local ufrag that we should return a password  
for.
-     *
-     * @return this handler's parent agent local password if  
<tt>username</tt>
-     * equals the local ufrag and <tt>null</tt> otherwise.
-     */
-    public byte[] getKey(String username)
-    {
-        //support both the case where username is the local fragment or the
-        //entire user name.
-        int colon = username.indexOf(":");
-        if( colon < 0)
-        {
-            //caller gave us a ufrag
-            if (username.equals(parentAgent.getLocalUfrag()))
-                return parentAgent.getLocalPassword().getBytes();
-        }
-        else
-        {
-            //caller gave us the entire username.
-            if (username.equals(parentAgent.generateRemoteUserName()))
-                return parentAgent.getLocalPassword().getBytes();
-        }
-
-        return null;
-    }
-}
=======================================
--- /trunk/src/org/ice4j/attribute/AttributeFactory.java	Sun Apr 25  
07:42:38 2010
+++ /trunk/src/org/ice4j/attribute/AttributeFactory.java	Tue Apr 27  
16:31:58 2010
@@ -335,19 +335,17 @@
       * the HMAC-SHA1 (RFC 2104) would correspond to the actual message  
that's
       * transporting the attribute.
       *
-     * @param key the key that we should use when creating the HMAC-SHA1.
+     * @param username the username that we should use to obtain an  
encryption
+     * key (password) that the {@link Attribute#encode()} method should  
use when
+     * creating the content of this message.
       *
       * @return the newly created address attribute.
       */
      public static MessageIntegrityAttribute  
createMessageIntegrityAttribute(
-                                                    byte[] key)
+                                                    String username)
      {
          MessageIntegrityAttribute attribute = new  
MessageIntegrityAttribute();
-
-        attribute.setKey(key);
-
-        //todo: implement saslprep one day even though I don't think it's
-        //necessary for the ICE use case.
+        attribute.setUsername(username);

          return attribute;
      };
=======================================
--- /trunk/src/org/ice4j/attribute/MessageIntegrityAttribute.java	Mon Apr  
26 14:34:03 2010
+++ /trunk/src/org/ice4j/attribute/MessageIntegrityAttribute.java	Tue Apr  
27 16:31:58 2010
@@ -14,6 +14,7 @@
  import javax.crypto.spec.*;

  import org.ice4j.*;
+import org.ice4j.stack.*;

  /**
   * The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of
@@ -100,9 +101,11 @@
      private byte[] hmacSha1Content;

      /**
-     * The key that we should be using when creating the hmacSha1Content.
+     * The username that we should use to obtain an encryption
+     * key (password) that the {@link #encode()} method should use when
+     * creating the content of this message.
       */
-    private byte[] key;
+    private String username;

      /**
       * Creates a <tt>MessageIntegrityAttribute</tt>.
@@ -113,15 +116,17 @@
      }

      /**
-     * Sets the key that the {@link #encode()} method should use when  
creating
-     * the content of this message.
+     * Sets the username that we should use to obtain an encryption
+     * key (password) that the {@link #encode()} method should use when
+     * creating the content of this message.
       *
-     * @param key the key that the {@link #encode()} method should use when
+     * @param username the username that we should use to obtain an  
encryption
+     * key (password) that the {@link #encode()} method should use when
       * creating the content of this message.
       */
-    public void setKey(byte[] key)
-    {
-        this.key = key;
+    public void setUsername(String username)
+    {
+        this.username = username;
      }

      /**
@@ -249,9 +254,11 @@
          binValue[2] = (byte)(getDataLength()>>8);
          binValue[3] = (byte)(getDataLength()&0x00FF);

+        byte[] key = StunStack.getInstance().getCredentialsManager()
+            .getKey(username);
+
          //now calculate the HMAC-SHA1
-        this.hmacSha1Content = calculateHmacSha1(
-                        content, offset, length, this.key);
+        this.hmacSha1Content = calculateHmacSha1(content, offset, length,  
key);

          //username
          System.arraycopy(hmacSha1Content, 0, binValue, 4, getDataLength());
=======================================
--- /trunk/src/org/ice4j/ice/Agent.java	Mon Apr 26 14:32:47 2010
+++ /trunk/src/org/ice4j/ice/Agent.java	Tue Apr 27 16:31:58 2010
@@ -103,11 +103,16 @@
      private boolean isControlling = true;

      /**
-     * The entity that will be taking care of all incoming and outgoing
-     * connectivity checks.
+     * The entity that will be taking care of outgoing connectivity checks.
       */
-    private final ConnectivityCheckHandler connCheckHandler
-                                = new ConnectivityCheckHandler(this);
+    private final ConnectivityCheckClient connCheckHandler
+                                = new ConnectivityCheckClient(this);
+
+    /**
+     * The entity that will be taking care of incoming connectivity checks.
+     */
+    private final ConnectivityCheckServer connCheckServer
+                                = new ConnectivityCheckServer(this);

      /**
       * Creates an empty <tt>Agent</tt> with no streams, and no address
=======================================
--- /trunk/src/org/ice4j/ice/ConnectivityCheckServer.java	Sun Apr 25  
07:39:54 2010
+++ /trunk/src/org/ice4j/ice/ConnectivityCheckServer.java	Tue Apr 27  
16:31:58 2010
@@ -6,34 +6,140 @@
   */
  package org.ice4j.ice;

+import java.util.logging.*;
+
  import org.ice4j.*;
+import org.ice4j.attribute.*;
+import org.ice4j.message.*;
+import org.ice4j.security.*;
  import org.ice4j.stack.*;
  /**
   * @author Emil Ivov
   */
  public class ConnectivityCheckServer
-    implements RequestListener
-{
+    implements RequestListener,
+               CredentialsAuthority
+{
+    /**
+     * The <tt>Logger</tt> used by the <tt>ConnectivityCheckServer</tt>
+     * class and its instances for logging output.
+     */
+    private static final Logger logger = Logger
+                    .getLogger(ConnectivityCheckServer.class.getName());
+
+    /**
+     * The agent that created us.
+     */
+    private final Agent parentAgent;
+
+    /**
+     * The stun stack that we will use for connectivity checks.
+     */
      StunStack stunStack = StunStack.getInstance();

-    public ConnectivityCheckServer()
-    {
+    /**
+     * Creates a new <tt>ConnectivityCheckServer</tt> setting
+     * <tt>parentAgent</tt> as the agent that will be used for retrieving
+     * information such as user fragments for example.
+     *
+     * @param parentAgent the <tt>Agent</tt> that is creating this  
instance.
+     */
+    public ConnectivityCheckServer(Agent parentAgent)
+    {
+        this.parentAgent = parentAgent;
          stunStack.addRequestListener(this);
+        stunStack.getCredentialsManager().registerAuthority(this);
      }

-    public void startListening(LocalCandidate candidate)
-    {
-        stunStack.addSocket(candidate.getSocket());
+    public void requestReceived(StunMessageEvent evt)
+    {
+        Request request = (Request)evt.getMessage();
+
+        //ignore incoming requests that are not meant for the local user.
+        //normally the stack will get rid of faulty user names but we could
+        //still see messages not meant for this server if both peers or  
running
+        //on this same instance of the stack.
+        UsernameAttribute uname = (UsernameAttribute)request
+            .getAttribute(Attribute.USERNAME);
+
+        if(uname == null
+           || !checkUserName(new String(uname.getUsername())))
+        {
+            return;
+        }
+
+        //check message integrity.
+        Response response = MessageFactory.createBindingResponse(
+                        request, evt.getRemoteAddress());
+        try
+        {
+             
stunStack.sendResponse(evt.getTransactionID().getTransactionID(),
+                response, evt.getLocalAddress(), evt.getRemoteAddress());
+        }
+        catch (Exception e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
      }

-    public void stopListenint(LocalCandidate candidate)
-    {
-        stunStack.removeSocket(candidate.getTransportAddress());
+    /**
+     * Verifies whether <tt>username</tt> is currently known to this server
+     * and returns <tt>true</tt> if so. Returns <tt>false</tt> otherwise.
+     *
+     * @param username the user name whose validity we'd like to check.
+     *
+     * @return <tt>true</tt> if <tt>username</tt> is known to this
+     * <tt>ConnectivityCheckServer</tt> and <tt>false</tt> otherwise.
+     */
+    public boolean checkUserName(String username)
+    {
+        boolean accept = false;
+        int colon = username.indexOf(":");
+        if( colon < 0)
+        {
+            //caller gave us a ufrag
+            if(username.equals(parentAgent.getLocalUfrag()))
+                accept = true;
+        }
+        else
+        {
+            //caller gave us the entire username.
+            if(username.substring(0,  
colon).equals(parentAgent.getLocalUfrag()))
+                accept = true;
+        }
+        return accept;
      }

-    public void requestReceived(StunMessageEvent evt)
-    {
-        System.out.println("evt=" + evt);
-    }
-
-}
+    /**
+     * Implements the {@link CredentialsAuthority#getKey(String)} method  
in a
+     * way that would return this handler's parent agent password if
+     * <tt>username</tt> is either the local ufrag or the username that the
+     * agent's remote peer was expected to use.
+     *
+     * @param username the local ufrag that we should return a password  
for.
+     *
+     * @return this handler's parent agent local password if  
<tt>username</tt>
+     * equals the local ufrag and <tt>null</tt> otherwise.
+     */
+    public byte[] getKey(String username)
+    {
+        //support both the case where username is the local fragment or the
+        //entire user name.
+        int colon = username.indexOf(":");
+        if( colon < 0)
+        {
+            //caller gave us a ufrag
+            if (username.equals(parentAgent.getLocalUfrag()))
+                return parentAgent.getLocalPassword().getBytes();
+        }
+        else
+        {
+            //caller gave us the entire username.
+            if (username.equals(parentAgent.generateRemoteUserName()))
+                return parentAgent.getLocalPassword().getBytes();
+        }
+
+        return null;
+    }
+}
=======================================
--- /trunk/src/org/ice4j/message/Message.java	Mon Apr 26 14:33:50 2010
+++ /trunk/src/org/ice4j/message/Message.java	Tue Apr 27 16:31:58 2010
@@ -678,35 +678,75 @@
                  binMessage, (char)initialOffset,
                      (char)(offset - initialOffset)); // message head

-            //assert Message Integrity
-            if (att instanceof MessageIntegrityAttribute)
-            {
-                if (!message.validateMessageIntegrity(
-                                (MessageIntegrityAttribute)att,
-                                binMessage, originalOffset, offset))
-                {
-                    throw new StunException(StunException.ILLEGAL_ARGUMENT,
-                                    "Wrong value in MESSAGE-INTEGRITY");
-                }
-
+            performAttributeSpecificActions(att, binMessage, message,
+                            originalOffset, offset);
+
+            message.addAttribute(att);
+            offset += att.getDataLength() + Attribute.HEADER_LENGTH;
+        }
+
+        return message;
+    }
+
+    /**
+     * Executes actions related specific attributes like asserting proper
+     * checksums or verifying the validity of user names.
+     *
+     * @param attribute the <tt>Attribute</tt> we'd like to process.
+     * @param binMessage the byte array that the message arrived with.
+     * @param message the <tt>Message</tt> that we're parsing
+     * <tt>binMessage</tt> into.
+     * @param offset the index where data starts in <tt>binMessage</tt>.
+     * @param msgLen the number of message bytes in <tt>binMessage</tt>.
+     *
+     * @throws StunException if there's something in the <tt>attribute</tt>
+     * that caused us to discard the whole message (e.g. an invalid  
checksum
+     * or username)
+     */
+    private static void performAttributeSpecificActions(Attribute  
attribute,
+                                                        byte[]     
binMessage,
+                                                        Message   message,
+                                                        int       offset,
+                                                        int       msgLen)
+        throws StunException
+    {
+        //assert valid username
+        if (attribute instanceof UsernameAttribute)
+        {
+            if (!validateUsername( (UsernameAttribute)attribute))
+            {
+                throw new StunException(StunException.ILLEGAL_ARGUMENT,
+                    "Non-recognized username: "
+                    + new String(((UsernameAttribute)attribute)
+                                        .getUsername()) );
              }

-            //check finger print CRC
-            if (att instanceof FingerprintAttribute)
-            {
-                if (!validateFingerprint((FingerprintAttribute)att,
-                                binMessage, originalOffset, offset))
-                {
-                    throw new StunException(StunException.ILLEGAL_ARGUMENT,
-                                    "Wrong value in FINGERPRINT");
-                }
-
+        }
+
+        //assert Message Integrity
+        if (attribute instanceof MessageIntegrityAttribute)
+        {
+            if (!message.validateMessageIntegrity(
+                            (MessageIntegrityAttribute)attribute,
+                            binMessage, offset, msgLen))
+            {
+                throw new StunException(StunException.ILLEGAL_ARGUMENT,
+                                "Wrong value in MESSAGE-INTEGRITY");
+            }
+
+        }
+
+        //check finger print CRC
+        if (attribute instanceof FingerprintAttribute)
+        {
+            if (!validateFingerprint((FingerprintAttribute)attribute,
+                            binMessage, offset, msgLen))
+            {
+                throw new StunException(StunException.ILLEGAL_ARGUMENT,
+                                "Wrong value in FINGERPRINT");
              }

-            message.addAttribute(att);
-            offset += att.getDataLength() + Attribute.HEADER_LENGTH;
-        }
-        return message;
+        }
      }

      /**
@@ -723,10 +763,10 @@
       * @return <tt>true</tt> if <tt>fingerprint</tt> contains a valid CRC32
       * value and <tt>false</tt> otherwise.
       */
-    public static boolean validateFingerprint(FingerprintAttribute  
fingerprint,
-                                              byte[]               message,
-                                              int                  offset,
-                                              int                  length)
+    private static boolean validateFingerprint(FingerprintAttribute  
fingerprint,
+                                               byte[]                
message,
+                                               int                  offset,
+                                               int                  length)
      {

          byte[] incomingCrcBytes = fingerprint.getChecksum();
@@ -769,10 +809,10 @@
       * @return <tt>true</tt> if <tt>msgInt</tt> contains a valid SHA1  
value and
       * <tt>false</tt> otherwise.
       */
-    public boolean validateMessageIntegrity(MessageIntegrityAttribute  
msgInt,
-                                            byte[]                     
message,
-                                            int                        
offset,
-                                            int                        
length)
+    private boolean validateMessageIntegrity(MessageIntegrityAttribute  
msgInt,
+                                             byte[]                     
message,
+                                             int                        
offset,
+                                             int                        
length)
      {
          //first get a password for the username specified with this  
message.
          UsernameAttribute unameAttr
@@ -828,6 +868,38 @@

          return true;
      }
+
+    /**
+     * Asserts the validity of the user name we've received in
+     * <tt>unameAttr</tt>.
+     *
+     * @param unameAttr the attribute that we need to validate.
+     *
+     * @return <tt>true</tt> if <tt>unameAttr</tt> contains a valid user  
name
+     * and <tt>false</tt> otherwise.
+     */
+    private static boolean validateUsername(UsernameAttribute unameAttr)
+    {
+        String username = new String(unameAttr.getUsername());
+
+        int colon = username.indexOf(":");
+
+        if( username.length() < 1
+            || colon < 1)
+        {
+            if(logger.isLoggable(Level.FINE))
+            {
+                logger.log(Level.FINE, "Received a message with an  
improperly "
+                        +"formatted username");
+            }
+            return false;
+        }
+
+        String lfrag = username.substring(0, colon);
+
+        return StunStack.getInstance()
+                .getCredentialsManager().checkUserName(lfrag);
+    }

      /**
       * Verify that the message has all obligatory attributes and throw an
=======================================
--- /trunk/src/org/ice4j/security/CredentialsAuthority.java	Mon Apr 26  
14:32:47 2010
+++ /trunk/src/org/ice4j/security/CredentialsAuthority.java	Tue Apr 27  
16:31:58 2010
@@ -29,4 +29,15 @@
       * <tt>CredentialsAuthority</tt>.
       */
      public byte[] getKey(String username);
-}
+
+    /**
+     * Verifies whether <tt>username</tt> is currently known to this  
authority
+     * and returns <tt>true</tt> if so. Returns <tt>false</tt> otherwise.
+     *
+     * @param username the user name whose validity we'd like to check.
+     *
+     * @return <tt>true</tt> if <tt>username</tt> is known to this
+     * <tt>CredentialsAuthority</tt> and <tt>false</tt> otherwise.
+     */
+    public boolean checkUserName(String username);
+}
=======================================
--- /trunk/src/org/ice4j/security/CredentialsManager.java	Mon Apr 26  
14:32:47 2010
+++ /trunk/src/org/ice4j/security/CredentialsManager.java	Tue Apr 27  
16:31:58 2010
@@ -52,11 +52,36 @@
              byte[] passwd = auth.getKey(username);

              if (passwd != null)
+            {
+                /** @todo: we should probably add SASLprep here.*/
                  return passwd;
+            }
          }

          return null;
      }
+
+    /**
+     * Verifies whether <tt>username</tt> is currently known to any of the
+     * {@link CredentialsAuthority}s registered with this manager and
+     * and returns <tt>true</tt> if so. Returns <tt>false</tt> otherwise.
+     *
+     * @param username the user name whose validity we'd like to check.
+     *
+     * @return <tt>true</tt> if <tt>username</tt> is known to any of the
+     * <tt>CredentialsAuthority</tt>s registered here and <tt>false</tt>
+     * otherwise.
+     */
+    public boolean checkUserName(String username)
+    {
+        for (CredentialsAuthority auth : authorities)
+        {
+            if( auth.checkUserName(username))
+                return true;
+        }
+
+        return false;
+    }

      /**
       * Adds <tt>authority</tt> to the list of {@link CredentialsAuthority}s
=======================================
--- /trunk/src/org/ice4j/stack/NetAccessManager.java	Mon Feb 15 07:53:00  
2010
+++ /trunk/src/org/ice4j/stack/NetAccessManager.java	Tue Apr 27 16:31:58  
2010
@@ -93,7 +93,10 @@
          /**
           * apart from logging, i am not sure what else we could do here.
           */
-        logger.log( Level.WARNING, "The following error occurred", error);
+        logger.log( Level.FINE,
+                        "The following error occurred with "
+                        +"an incoming message:",
+                        error);
      }

      /**

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe at sip-communicator.dev.java.net
For additional commands, e-mail: commits-help at sip-communicator.dev.java.net





More information about the commits mailing list