Secure LLDP-based Topology Detection

Current LLDP/BDDP-based Topology Detection is vulnerable to the
creation of fake links via forged, modified, or replayed LLDP packets.
This patch fixes this vulnerability by authenticating LLDP/BDDP packets
using a Message Authentication Code and adding a timestamp to prevent
replay. We use HMAC with SHA-256 has our Messge Authentication Code and
derive the key from the config/cluster.json file via the
ClusterMetadata class.

Change-Id: I01dd6edc5cffd6dfe274bcdb97189f2661a6c4f1
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java b/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
index d5ef232..de7a3e1 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/ConfigFileBasedClusterMetadataProvider.java
@@ -119,6 +119,7 @@
                 .stream()
                 .map(this::toPrototype)
                 .collect(Collectors.toSet()));
+        prototype.setClusterSecret(metadata.getClusterSecret());
         return prototype;
     }
 
@@ -274,7 +275,8 @@
                     metadata.getStorage()
                         .stream()
                         .map(node -> new DefaultControllerNode(getNodeId(node), getNodeHost(node), getNodePort(node)))
-                        .collect(Collectors.toSet())),
+                        .collect(Collectors.toSet()),
+                    metadata.getClusterSecret()),
                 version);
         } catch (IOException e) {
             throw new IllegalArgumentException(e);
@@ -307,6 +309,7 @@
         private NodePrototype node;
         private Set<NodePrototype> controller = Sets.newHashSet();
         private Set<NodePrototype> storage = Sets.newHashSet();
+        private String clusterSecret;
 
         public String getName() {
             return name;
@@ -339,6 +342,14 @@
         public void setStorage(Set<NodePrototype> storage) {
             this.storage = storage;
         }
+
+        public void setClusterSecret(String clusterSecret) {
+            this.clusterSecret = clusterSecret;
+        }
+
+        public String getClusterSecret() {
+            return clusterSecret;
+        }
     }
 
     private static class NodePrototype {
@@ -379,4 +390,4 @@
             this.port = port;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/DefaultClusterMetadataProvider.java b/core/net/src/main/java/org/onosproject/cluster/impl/DefaultClusterMetadataProvider.java
index a6f24ae..35a56a8 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/DefaultClusterMetadataProvider.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/DefaultClusterMetadataProvider.java
@@ -20,6 +20,7 @@
 import java.net.NetworkInterface;
 import java.util.Collections;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Function;
 
@@ -73,7 +74,8 @@
         ControllerNode localNode =
                 new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT);
         ClusterMetadata metadata = new ClusterMetadata(
-            PROVIDER_ID, "default", localNode, ImmutableSet.of(), ImmutableSet.of());
+            PROVIDER_ID, "default", localNode, ImmutableSet.of(), ImmutableSet.of(),
+            UUID.randomUUID().toString());
         long version = System.currentTimeMillis();
         cachedMetadata.set(new Versioned<>(metadata, version));
         providerRegistry.register(this);