Add automatic NLSR security configuration

refs: #3050

Change-Id: I218f96a2cb11dd35de99c4a9eab056f0fed890aa
diff --git a/bin/minindn b/bin/minindn
index a9f0e9c..d70cc2f 100755
--- a/bin/minindn
+++ b/bin/minindn
@@ -1,8 +1,8 @@
 # -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
 #
-# Copyright (C) 2015 The University of Memphis,
-#                    Arizona Board of Regents,
-#                    Regents of the University of California.
+# Copyright (C) 2015-2016, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
 #
 # This file is part of Mini-NDN.
 # See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
@@ -104,6 +104,7 @@
         self.templateFile = "minindn.conf"
         self.hr = False
         self.isCliEnabled = True
+        self.nlsrSecurity = False
         self.nPings = 300
         self.testbed = False
         self.workDir = "/tmp"
@@ -161,6 +162,9 @@
     parser.add_option("--nPings", action="store", dest="nPings", type="int", default=300,
     help="Number of pings to perform between each node in the experiment")
 
+    parser.add_option("--nlsr-security", action="store_true", dest="nlsrSecurity", default=False,
+    help="Enables NLSR security")
+
     parser.add_option("-t", "--testbed", action="store_true", dest="testbed", default=False,
     help="instantiates NDN Testbed")
 
@@ -184,7 +188,9 @@
     options.nFaces = args.faces
     options.hr = args.hr
     options.isCliEnabled = args.isCliEnabled
+    options.nlsrSecurity = args.nlsrSecurity
     options.nPings = args.nPings
+
     options.testbed = args.testbed
     options.workDir = args.workDir
     options.resultDir = args.resultDir
@@ -308,6 +314,10 @@
 
     nodes = ""    # Used later to check prefix name in checkFIB
 
+    # NLSR Security
+    if options.nlsrSecurity is True:
+        Nlsr.createKeysAndCertificates(net, options.workDir)
+
     # NLSR initialization
     for host in net.hosts:
         nodes += str(host.name) + ","
@@ -322,7 +332,7 @@
             host.nlsrParameters["hyperbolic-state"] = "on"
 
         # Generate NLSR configuration file
-        configGenerator = NlsrConfigGenerator(host)
+        configGenerator = NlsrConfigGenerator(host, options.nlsrSecurity)
         configGenerator.createConfigFile()
 
         # Start NLSR
diff --git a/ndn/nlsr.py b/ndn/nlsr.py
index 38cda67..da68f76 100644
--- a/ndn/nlsr.py
+++ b/ndn/nlsr.py
@@ -1,8 +1,8 @@
 # -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
 #
-# Copyright (C) 2015 The University of Memphis,
-#                    Arizona Board of Regents,
-#                    Regents of the University of California.
+# Copyright (C) 2015-2016, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
 #
 # This file is part of Mini-NDN.
 # See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
@@ -21,8 +21,14 @@
 # along with Mini-NDN, e.g., in COPYING.md file.
 # If not, see <http://www.gnu.org/licenses/>.
 
+from mininet.clean import sh
+
 from ndn.ndn_application import NdnApplication
 
+import os
+import shutil
+import textwrap
+
 class Nlsr(NdnApplication):
     def __init__(self, node):
         NdnApplication.__init__(self, node)
@@ -42,14 +48,71 @@
     def start(self):
         NdnApplication.start(self, "nlsr -d -f {} &".format(self.confFile))
 
+    @staticmethod
+    def createKey(host, name, outputFile):
+        host.cmd("ndnsec-keygen {} > {}".format(name, outputFile))
+
+    @staticmethod
+    def createCertificate(host, name, prefix, keyFile, outputFile, signer=None):
+        if signer is None:
+            host.cmd("ndnsec-certgen -N {} -p {} {} > {}".format(name, prefix, keyFile, outputFile))
+        else:
+            host.cmd("ndnsec-certgen -N {} -p {} -s {} {} > {}".format(name, prefix, signer, keyFile, outputFile))
+
+    @staticmethod
+    def createKeysAndCertificates(net, workDir):
+        securityDir = "{}/security".format(workDir)
+
+        if not os.path.exists(securityDir):
+                os.mkdir(securityDir)
+
+        # Create root certificate
+        rootName = "/ndn"
+        sh("ndnsec-keygen {} > {}/root.keys".format(rootName, securityDir))
+        sh("ndnsec-certgen -N {} -p {} {}/root.keys > {}/root.cert".format(rootName, rootName, securityDir, securityDir))
+
+        # Create necessary certificates for each site
+        for host in net.hosts:
+            nodeSecurityFolder = "{}/security".format(host.homeFolder)
+
+            if not os.path.exists(nodeSecurityFolder):
+                os.mkdir(nodeSecurityFolder)
+
+            shutil.copyfile("{}/root.cert".format(securityDir), "{}/root.cert".format(nodeSecurityFolder))
+
+            # Create site certificate
+            siteName = "/ndn/edu"
+            siteKeyFile = "{}/site.keys".format(nodeSecurityFolder)
+            siteCertFile = "{}/site.cert".format(nodeSecurityFolder)
+            Nlsr.createKey(host, siteName, siteKeyFile)
+
+            # Root key is in root namespace, must sign site key and then install on host
+            sh("ndnsec-certgen -N {} -s {} -p {} {} > {}".format(siteName, rootName, siteName, siteKeyFile, siteCertFile))
+            host.cmd("ndnsec-cert-install -f {}".format(siteCertFile))
+
+            # Create operator certificate
+            opName = "{}/%C1.Operator/op".format(siteName)
+            opKeyFile = "{}/op.keys".format(nodeSecurityFolder)
+            opCertFile = "{}/op.cert".format(nodeSecurityFolder)
+            Nlsr.createKey(host, opName, opKeyFile)
+            Nlsr.createCertificate(host, opName, opName, opKeyFile, opCertFile, signer=siteName)
+
+            # Create router certificate
+            routerName = "{}/%C1.Router/cs/{}".format(siteName, host.name)
+            routerKeyFile = "{}/router.keys".format(nodeSecurityFolder)
+            routerCertFile = "{}/router.cert".format(nodeSecurityFolder)
+            Nlsr.createKey(host, routerName, routerKeyFile)
+            Nlsr.createCertificate(host, routerName, routerName, routerKeyFile, routerCertFile, signer=opName)
+
 class NlsrConfigGenerator:
 
     ROUTING_LINK_STATE = "ls"
     ROUTING_HYPERBOLIC = "hr"
 
-    def __init__(self, node):
+    def __init__(self, node, isSecurityEnabled):
         node.cmd("sudo cp /usr/local/etc/mini-ndn/nlsr.conf nlsr.conf")
         self.node = node
+        self.isSecurityEnabled = isSecurityEnabled
 
         parameters = node.nlsrParameters
 
@@ -72,6 +135,7 @@
         newContent = newContent.replace("$HYPERBOLIC_SECTION", self.__getHyperbolicSection())
         newContent = newContent.replace("$FIB_SECTION", self.__getFibSection())
         newContent = newContent.replace("$ADVERTISING_SECTION", self.__getAdvertisingSection())
+        newContent = newContent.replace("$SECURITY_SECTION", self.__getSecuritySection())
 
         configFile = open(filePath, 'w')
         configFile.write(newContent)
@@ -162,16 +226,196 @@
         return advertising
 
     def __getSecuritySection(self):
+        if self.isSecurityEnabled is False:
+            security = textwrap.dedent("""\
+                security
+                {
+                  validator
+                  {
+                    trust-anchor
+                    {
+                      type any
+                    }
+                  }
+                  prefix-update-validator
+                  {
+                    trust-anchor
+                    {
+                      type any
+                    }
+                  }
+                }""")
+        else:
+            security = textwrap.dedent("""\
+                security
+                {
+                  validator
+                  {
+                    rule
+                    {
+                      id "NSLR Hello Rule"
+                      for data
+                      filter
+                      {
+                        type name
+                        regex ^[^<NLSR><INFO>]*<NLSR><INFO><><>$
+                      }
+                      checker
+                      {
+                        type customized
+                        sig-type rsa-sha256
+                        key-locator
+                        {
+                          type name
+                          hyper-relation
+                          {
+                            k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
+                            k-expand \\\\1
+                            h-relation equal
+                            p-regex ^([^<NLSR><INFO>]*)<NLSR><INFO><><>$
+                            p-expand \\\\1
+                          }
+                        }
+                      }
+                    }
 
-        security =  "security\n"
-        security += "{\n"
-        security += "  validator\n"
-        security += "  {\n"
-        security += "    trust-anchor\n"
-        security += "    {\n"
-        security += "      type any\n"
-        security += "    }\n"
-        security += "  }\n"
-        security += "}\n"
+                    rule
+                    {
+                      id "NSLR LSA Rule"
+                      for data
+                      filter
+                      {
+                        type name
+                        regex ^[^<NLSR><LSA>]*<NLSR><LSA>
+                      }
+                      checker
+                      {
+                        type customized
+                        sig-type rsa-sha256
+                        key-locator
+                        {
+                          type name
+                          hyper-relation
+                          {
+                            k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
+                            k-expand \\\\1
+                            h-relation equal
+                            p-regex ^([^<NLSR><LSA>]*)<NLSR><LSA>(<>*)<><><><>$
+                            p-expand \\\\1\\\\2
+                          }
+                        }
+                      }
+                    }
+
+                    rule
+                    {
+                      id "NSLR Hierarchy Exception Rule"
+                      for data
+                      filter
+                      {
+                        type name
+                        regex ^[^<KEY><%C1.Router>]*<%C1.Router>[^<KEY><NLSR>]*<KEY><ksk-.*><ID-CERT><>$
+                      }
+                      checker
+                      {
+                        type customized
+                        sig-type rsa-sha256
+                        key-locator
+                        {
+                          type name
+                          hyper-relation
+                          {
+                            k-regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
+                            k-expand \\\\1
+                            h-relation equal
+                            p-regex ^([^<KEY><%C1.Router>]*)<%C1.Router>[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
+                            p-expand \\\\1
+                          }
+                        }
+                      }
+                    }
+
+                    rule
+                    {
+                      id "NSLR Hierarchical Rule"
+                      for data
+                      filter
+                      {
+                        type name
+                        regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
+                      }
+                      checker
+                      {
+                        type hierarchical
+                        sig-type rsa-sha256
+                      }
+                    }
+
+                    trust-anchor
+                    {
+                      type file
+                      file-name "security/root.cert"
+                    }
+                  }
+
+                  prefix-update-validator
+                  {
+                    rule
+                    {
+                      id "NLSR ControlCommand Rule"
+                      for interest
+                      filter
+                      {
+                        type name
+                        regex ^<localhost><nlsr><prefix-update>[<advertise><withdraw>]<>$
+                      }
+                      checker
+                      {
+                        type customized
+                        sig-type rsa-sha256
+                        key-locator
+                        {
+                          type name
+                          regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
+                        }
+                      }
+                    }
+
+                    rule
+                    {
+                      id "NLSR Hierarchy Rule"
+                      for data
+                      filter
+                      {
+                        type name
+                        regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
+                      }
+                      checker
+                      {
+                        type hierarchical
+                        sig-type rsa-sha256
+                      }
+                    }
+
+                    trust-anchor
+                    {
+                      type file
+                      file-name "security/site.cert"
+                    }
+                  }
+                  ; cert-to-publish "security/root.cert"  ; optional, a file containing the root certificate
+                                                 ; Only the router that is designated to publish the root cert
+                                                 ; needs to specify this
+
+                  cert-to-publish "security/site.cert"  ; optional, a file containing the site certificate
+                                                 ; Only the router that is designated to publish the site cert
+                                                 ; needs to specify this
+
+                  cert-to-publish "security/op.cert" ; optional, a file containing the operator certificate
+                                                    ; Only the router that is designated to publish the operator
+                                                    ; cert needs to specify this
+
+                  cert-to-publish "security/router.cert"  ; required, a file containing the router certificate.
+                }""")
 
         return security
diff --git a/ndn_utils/nlsr.conf b/ndn_utils/nlsr.conf
index 1eb56de..492ee0d 100644
--- a/ndn_utils/nlsr.conf
+++ b/ndn_utils/nlsr.conf
@@ -21,174 +21,4 @@
 
 $ADVERTISING_SECTION
 
-security
-{
-  validator
-  {
-    rule
-    {
-      id "NSLR Hello Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<NLSR><INFO>]*<NLSR><INFO><><>$
-      }
-      checker
-      {
-        type customized
-        sig-type rsa-sha256
-        key-locator
-        {
-          type name
-          hyper-relation
-          {
-            k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
-            k-expand \\1
-            h-relation equal
-            p-regex ^([^<NLSR><INFO>]*)<NLSR><INFO><><>$
-            p-expand \\1
-          }
-        }
-      }
-    }
-
-    rule
-    {
-      id "NSLR LSA Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<NLSR><LSA>]*<NLSR><LSA>
-      }
-      checker
-      {
-        type customized
-        sig-type rsa-sha256
-        key-locator
-        {
-          type name
-          hyper-relation
-          {
-            k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
-            k-expand \\1
-            h-relation equal
-            p-regex ^([^<NLSR><LSA>]*)<NLSR><LSA>(<>*)<><><>$
-            p-expand \\1\\2
-          }
-        }
-      }
-    }
-
-    rule
-    {
-      id "NSLR Hierarchy Exception Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<KEY><%C1.Router>]*<%C1.Router>[^<KEY><NLSR>]*<KEY><ksk-.*><ID-CERT><>$
-      }
-      checker
-      {
-        type customized
-        sig-type rsa-sha256
-        key-locator
-        {
-          type name
-          hyper-relation
-          {
-	    k-regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
-            k-expand \\1
-            h-relation equal
-            p-regex ^([^<KEY><%C1.Router>]*)<%C1.Router>[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
-            p-expand \\1
-          }
-        }
-      }
-    }
-
-    rule
-    {
-      id "NSLR Hierarchical Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
-      }
-      checker
-      {
-        type hierarchical
-        sig-type rsa-sha256
-      }
-    }
-
-    trust-anchor
-    {
-      type any
-      file-name "root.cert"
-    }
-  }
-
-  prefix-update-validator
-  {
-    rule
-    {
-      id "NLSR ControlCommand Rule"
-      for interest
-      filter
-      {
-        type name
-        regex ^<localhost><nlsr><prefix-update>[<advertise><withdraw>]<>$
-      }
-      checker
-      {
-        type customized
-        sig-type rsa-sha256
-        key-locator
-        {
-          type name
-          regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
-        }
-      }
-    }
-
-    rule
-    {
-      id "NLSR Hierarchy Rule"
-      for data
-      filter
-      {
-        type name
-        regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
-      }
-      checker
-      {
-        type hierarchical
-        sig-type rsa-sha256
-      }
-    }
-
-    trust-anchor
-    {
-      type any
-      file-name "site.cert"
-    }
-  }
-
-  ; cert-to-publish "root.cert"  ; optional, a file containing the root certificate
-                                 ; Only the router that is designated to publish the root cert
-                                 ; needs to specify this
-
-  ; cert-to-publish "site.cert"  ; optional, a file containing the site certificate
-                                 ; Only the router that is designated to publish the site cert
-                                 ; needs to specify this
-
-  ; cert-to-publish "operator.cert" ; optional, a file containing the operator certificate
-                                    ; Only the router that is designated to publish the operator
-                                    ; cert needs to specify this
-
-  ; cert-to-publish "router.cert"  ; required, a file containing the router certificate.
-}
+$SECURITY_SECTION