servlib/cmd/SecurityCommand.cc
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/cmd/SecurityCommand.cc	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2007 BBN Technologies Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <dtn-config.h>
+#endif
+
+#ifdef BSP_ENABLED
+
+#include <cstring>
+#include <cstdio>
+#include <oasys/util/Base16.h>
+
+#include "SecurityCommand.h"
+#include "security/SPD.h"
+#include "security/KeyDB.h"
+#include "security/Ciphersuite.h"
+
+namespace dtn {
+
+SecurityCommand::SecurityCommand()
+    : TclCommand("security")
+{
+    add_to_help("setpolicy [in | out] [pib] [pcb] [bab]",
+                "Set inbound or outbound policy to require the specified\n"
+                "combination of PIB, PCB, and/or BAB.");
+    add_to_help("setkey <host> <cs_num> <key>",
+                "Set the key to use for the specified host and ciphersuite\n"
+                "number.  <host> may also be the wildcard symbol \"*\".");
+    add_to_help("dumpkeys",
+                "Dump the contents of the keystore to the screen.");
+    add_to_help("flushkeys",
+                "Erase all keys from the keystore.");
+}
+
+int
+SecurityCommand::exec(int argc, const char** argv, Tcl_Interp* interp)
+{
+    (void)interp;
+
+    if (argc < 2) {
+        resultf("need a security subcommand");
+        return TCL_ERROR;
+    }
+
+    const char* cmd = argv[1];
+
+    if (strcmp(cmd, "setpolicy") == 0) {
+        // security setpolicy [in | out] [psb] [cb] [bab]
+        if (argc < 3 || argc > 6) {
+            wrong_num_args(argc, argv, 2, 3, 6);
+            return TCL_ERROR;
+        }
+
+        SPD::spd_direction_t direction;
+        if (strcmp(argv[2], "in") == 0)
+            direction = SPD::SPD_DIR_IN;
+        else if (strcmp(argv[2], "out") == 0)
+            direction = SPD::SPD_DIR_OUT;
+        else {
+            resultf("invalid direction argument \"%s\" (must be one of "
+                    "\"in\" or \"out\")", argv[2]);
+            return TCL_ERROR;
+        }
+        
+        int policy = SPD::SPD_USE_NONE;
+        for (int i = 3; i < argc; i++) {
+            if (strcmp(argv[i], "pib") == 0)
+                policy |= SPD::SPD_USE_PIB;
+            else if (strcmp(argv[i], "pcb") == 0)
+                policy |= SPD::SPD_USE_PCB;
+            else if (strcmp(argv[i], "bab") == 0)
+                policy |= SPD::SPD_USE_BAB;
+            else {
+                resultf("invalid argument \"%s\"", argv[i]);
+                return TCL_ERROR;
+            }
+        }
+
+        SPD::set_global_policy(direction, (SPD::spd_policy_t)policy);
+
+        return TCL_OK;
+
+    } else if (strcmp(cmd, "setkey") == 0) {
+        // security setkey <host> <cs_num> <key>
+        if (argc != 5) {
+            wrong_num_args(argc, argv, 2, 5, 5);
+            return TCL_ERROR;
+        }
+
+        const char* host_arg   = argv[2];
+        const char* cs_num_arg = argv[3];
+        const char* key_arg    = argv[4];
+
+        int cs_num;
+        if (sscanf(cs_num_arg, "%i", &cs_num) != 1) {
+            resultf("invalid cs_num argument \"%s\"", cs_num_arg);
+            return TCL_ERROR;
+        }
+        if (! KeyDB::validate_cs_num(cs_num)) {
+            resultf("invalid ciphersuite number %#x", cs_num);
+            return TCL_ERROR;
+        }
+
+        size_t key_arg_len = strlen(key_arg);
+        if ((key_arg_len % 2) != 0) {
+            resultf("invalid key argument (must be even length)");
+            return TCL_ERROR;
+        }
+
+        size_t key_len = key_arg_len / 2;
+        if (! KeyDB::validate_key_len(cs_num, &key_len)) {
+            resultf("wrong key length for ciphersuite (expected %d bytes)",
+                    (int)key_len);
+            return TCL_ERROR;
+        }
+            
+        // convert key from ASCII hexadecimal to raw bytes
+        u_char* key = new u_char[key_len];
+        for (int i = 0; i < (int)key_len; i++)
+        {
+            int b = 0;
+
+            for (int j = 0; j <= 1; j++)
+            {
+                int c = (int)key_arg[2*i+j];
+                b <<= 4;
+
+                if (c >= '0' && c <= '9')
+                    b |= c - '0';
+                else if (c >= 'A' && c <= 'F')
+                    b |= c - 'A' + 10;
+                else if (c >= 'a' && c <= 'f')
+                    b |= c - 'a' + 10;
+                else {
+                    resultf("invalid character '%c' in key argument",
+                            (char)c);
+                    delete key;
+                    return TCL_ERROR;
+                }
+            }
+            
+            key[i] = (u_char)(b);
+        }
+
+        KeyDB::Entry new_entry =
+            KeyDB::Entry(host_arg, cs_num, key, key_len);
+        KeyDB::set_key(new_entry);
+
+        delete key;
+        return TCL_OK;
+
+    } else if (strcmp(cmd, "dumpkeys") == 0) {
+        // security dumpkeys
+        if (argc != 2) {
+            wrong_num_args(argc, argv, 2, 2, 2);
+            return TCL_ERROR;
+        }
+
+        oasys::StringBuffer buf;
+        KeyDB::dump_header(&buf);
+        KeyDB::dump(&buf);
+        set_result(buf.c_str());
+        return TCL_OK;
+
+    } else if (strcmp(cmd, "flushkeys") == 0) {
+        // security flushkeys
+        if (argc != 2) {
+            wrong_num_args(argc, argv, 2, 2, 2);
+            return TCL_ERROR;
+        }
+
+        KeyDB::flush_keys();
+
+    } else {
+        resultf("no such security subcommand %s", cmd);
+        return TCL_ERROR;
+    }
+
+    return TCL_OK;
+}
+
+} // namespace dtn
+
+#endif  /* BSP_ENABLED */