servlib/security/Ciphersuite.cc
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/security/Ciphersuite.cc	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,545 @@
+/*
+ *    Copyright 2006 SPARTA Inc
+ * 
+ *    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.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <dtn-config.h>
+#endif
+
+#ifdef BSP_ENABLED
+
+#include "Ciphersuite.h"
+#include "BA_BlockProcessor.h"
+#include "Ciphersuite_BA1.h"
+#include "PI_BlockProcessor.h"
+#include "Ciphersuite_PI2.h"
+#include "PC_BlockProcessor.h"
+#include "Ciphersuite_PC3.h"
+#include "bundling/Bundle.h"
+#include "bundling/BundleDaemon.h"
+#include "bundling/BundleProtocol.h"
+#include "contacts/Link.h"
+#include "bundling/SDNV.h"
+
+namespace dtn {
+
+
+#define CS_MAX 1024
+Ciphersuite* Ciphersuite::ciphersuites_[CS_MAX];
+
+static const char* log = "/dtn/bundle/ciphersuite";
+
+bool Ciphersuite::inited = false;
+
+//----------------------------------------------------------------------
+Ciphersuite::Ciphersuite()
+//    : BlockProcessor(block_type)
+{
+    log_debug_p(log, "Ciphersuite::Ciphersuite()");
+}
+
+//----------------------------------------------------------------------
+Ciphersuite::~Ciphersuite()
+{ }
+
+//----------------------------------------------------------------------
+void
+Ciphersuite::register_ciphersuite(Ciphersuite* cs)
+{
+    log_debug_p(log, "Ciphersuite::register_ciphersuite()");
+    u_int16_t    num = cs->cs_num();
+    
+    if ( num <= 0 || num >= CS_MAX )
+        return;            //out of range
+        
+    // don't override an existing suite
+    ASSERT(ciphersuites_[num] == 0);
+    ciphersuites_[num] = cs;
+}
+
+//----------------------------------------------------------------------
+Ciphersuite*
+Ciphersuite::find_suite(u_int16_t num)
+{
+    Ciphersuite* ret = NULL;
+    log_debug_p(log, "Ciphersuite::find_suite()");
+    
+    if ( num > 0 && num < CS_MAX )  // entry for element zero is illegal
+        ret = ciphersuites_[num];
+
+    return ret;
+}
+
+//----------------------------------------------------------------------
+void
+Ciphersuite::init_default_ciphersuites()
+{
+    log_debug_p(log, "Ciphersuite::init_default_ciphersuites()");
+    if ( ! inited ) {
+        // register default block processor handlers
+        BundleProtocol::register_processor(new BA_BlockProcessor());
+        BundleProtocol::register_processor(new PI_BlockProcessor());
+        BundleProtocol::register_processor(new PC_BlockProcessor());
+        
+        // register mandatory ciphersuites
+        register_ciphersuite(new Ciphersuite_BA1());
+        register_ciphersuite(new Ciphersuite_PI2());
+        register_ciphersuite(new Ciphersuite_PC3());
+        
+        inited = true;
+    }
+}
+
+//----------------------------------------------------------------------
+u_int16_t
+Ciphersuite::cs_num(void)
+{
+
+    return 0;
+}
+
+//----------------------------------------------------------------------
+void
+Ciphersuite::parse(BlockInfo* block)
+{
+    Ciphersuite*    cs_owner = NULL;
+    BP_Local_CS*    locals = NULL;
+    u_char*         buf;
+    size_t          len;
+    u_int64_t       cs_flags;
+    u_int64_t       suite_num;
+    int             sdnv_len;
+    u_int64_t       security_correlator    = 0LL;
+    u_int64_t       field_length           = 0LL;
+    bool            has_source;    
+    bool            has_dest;      
+    bool            has_params;    
+    bool            has_correlator;
+    bool            has_result;   
+    EndpointIDVector::const_iterator iter;
+    
+// XXX/pl todo  think about a "const" version of parse() since there
+//              are several callers who need parsing but have a const block
+    
+    log_debug_p(log, "Ciphersuite::parse() block %p", block);
+    ASSERT(block != NULL);
+    
+    // preamble has already been parsed and stored, so we skip over it here
+//get the type
+//get flags sdnv
+//get length sdnv
+    
+    buf = block->contents().buf() + block->data_offset();
+    len = block->data_length();
+    
+//get ciphersuite and flags
+    sdnv_len = SDNV::decode(buf,
+                            len,
+                            &suite_num);
+    buf += sdnv_len;
+    len -= sdnv_len;
+
+    sdnv_len = SDNV::decode(buf,
+                            len,
+                            &cs_flags);
+    buf += sdnv_len;
+    len -= sdnv_len;
+
+    has_source     = (cs_flags & CS_BLOCK_HAS_SOURCE)     != 0;
+    has_dest       = (cs_flags & CS_BLOCK_HAS_DEST)       != 0;
+    has_params     = (cs_flags & CS_BLOCK_HAS_PARAMS)     != 0;
+    has_correlator = (cs_flags & CS_BLOCK_HAS_CORRELATOR) != 0;
+    has_result     = (cs_flags & CS_BLOCK_HAS_RESULT)     != 0;
+    log_debug_p(log, "Ciphersuite::parse() suite_num %llu cs_flags 0x%llx",
+                U64FMT(suite_num), U64FMT(cs_flags));
+    
+    cs_owner = dynamic_cast<Ciphersuite*>(find_suite(suite_num));
+    
+    if ( ciphersuites_[suite_num] != NULL )            // get specific subclass if it's present
+        cs_owner = ciphersuites_[suite_num];
+    
+    if ( block->locals() == NULL ) {
+        if ( cs_owner != NULL )
+            cs_owner->init_locals(block);                // get owning class to allocate locals
+        else
+            block->set_locals( new BP_Local_CS );
+    }
+    
+    locals = dynamic_cast<BP_Local_CS*>(block->locals());
+    ASSERT ( locals != NULL );
+
+    ASSERT ( suite_num < 65535 );
+    locals->set_owner_cs_num(suite_num);
+
+//set cs_flags
+    ASSERT ( cs_flags  < 65535  );
+    locals->set_cs_flags(cs_flags);
+    
+//get correlator, if present
+    if ( has_correlator ) {    
+        sdnv_len = SDNV::decode(buf,
+                                len,
+                                &security_correlator);
+        buf += sdnv_len;
+        len -= sdnv_len;
+    }
+    log_debug_p(log, "Ciphersuite::parse() correlator %llu",
+                U64FMT(security_correlator));
+    locals->set_correlator(security_correlator);
+    
+
+//get cs params length, and data
+    if ( has_params ) {    
+        sdnv_len = SDNV::decode(buf,
+                                len,
+                                &field_length);
+        buf += sdnv_len;
+        len -= sdnv_len;
+        // make sure the buffer has enough space, copy data in
+        locals->writable_security_params()->reserve(field_length);
+        memcpy( locals->writable_security_params()->end(), buf, field_length);
+        locals->writable_security_params()->set_len(field_length);
+        buf += field_length;
+        len -= field_length;
+        log_debug_p(log, "Ciphersuite::parse() security_params len %llu",
+                    U64FMT(field_length));
+    }
+    
+
+//get sec-src length and data
+    log_debug_p(log, "Ciphersuite::parse() eid_list().size() %zu has_source %u has_dest %u", 
+                block->eid_list().size(), has_source, has_dest);
+    
+    // XXX/pl - temp fix for blocks loaded from store
+    if ( block->eid_list().size() > 0 ) {
+        iter = block->eid_list().begin();
+        if ( has_source ) {    
+            locals->set_security_src( iter->str() );
+            iter++;
+        }
+        
+
+        //get sec-dest length and data
+        if ( has_dest ) {    
+            locals->set_security_dest( iter->str() );
+        }
+    }
+    
+
+ //get sec-result length and data, if present
+    if ( has_result ) {    
+        sdnv_len = SDNV::decode(buf,
+                                len,
+                                &field_length);
+        buf += sdnv_len;
+        len -= sdnv_len;
+        // make sure the buffer has enough space, copy data in
+        locals->writable_security_result()->reserve(field_length);
+        memcpy( locals->writable_security_result()->end(), buf, field_length);
+        locals->writable_security_result()->set_len(field_length);
+        buf += field_length;
+        len -= field_length;
+        
+    }
+    
+
+
+
+}
+
+
+//----------------------------------------------------------------------
+int
+Ciphersuite::reload_post_process(Bundle*       bundle,
+                                 BlockInfoVec* block_list,
+                                 BlockInfo*    block)
+{
+    (void)bundle;
+    (void)block_list;
+    (void)block;
+    
+    // Received blocks might be stored and reloaded and
+    // some fields aren't reset.
+    // This allows BlockProcessors to reestablish what they
+    // need. The default implementation does nothing.
+    // In general that's appropriate, as the BlockProcessor
+    // will have called parse() and that's the main need. 
+    // Individual ciphersuites can override this if their 
+    // usage requires it.
+    
+    block->set_reloaded(false);
+    return 0;
+
+}
+
+//----------------------------------------------------------------------
+void
+Ciphersuite::generate_preamble(BlockInfoVec* xmit_blocks,
+                               BlockInfo*    block,
+                               u_int8_t      type,
+                               u_int64_t     flags,
+                               u_int64_t     data_length)
+{
+    block->owner()->generate_preamble(xmit_blocks, block, type,
+                                      flags, data_length);
+}
+
+//----------------------------------------------------------------------
+bool
+Ciphersuite::destination_is_local_node(const Bundle*    bundle,
+                                       const BlockInfo* block)
+{
+    u_int16_t       cs_flags = 0;
+    EndpointID        local_eid = BundleDaemon::instance()->local_eid();
+    BP_Local_CS*    locals;
+    bool            result = false;     //default is "no" even in case of errors
+
+    log_debug_p(log, "Ciphersuite::destination_is_local_node()");
+    if ( block == NULL )
+        return false;
+        
+    if ( block->locals() == NULL )       // then the block is broken
+        return false;
+    
+    locals = dynamic_cast<BP_Local_CS*>(block->locals());
+    if ( locals == NULL )
+        return false;
+
+    cs_flags = locals->cs_flags();
+    
+    // this is a very clunky way to get the "base" portion of the bundle destination
+    std::string bundle_dest_str = bundle->dest().uri().scheme() + "://" +
+                                  bundle->dest().uri().host();
+    EndpointID        dest_node(bundle_dest_str);
+    
+    
+    // if this is security-dest, or there isn't one and this is bundle dest
+    if (  (  (cs_flags & Ciphersuite::CS_BLOCK_HAS_DEST) && (local_eid == locals->security_dest())) ||
+          ( !(cs_flags & Ciphersuite::CS_BLOCK_HAS_DEST) && (local_eid == dest_node)              )    ) 
+    {  //yes - this is ours 
+        result = true;
+    }
+    
+    return result;
+}
+
+//----------------------------------------------------------------------
+bool
+Ciphersuite::source_is_local_node(const Bundle* bundle, const BlockInfo* block)
+{
+    u_int16_t       cs_flags = 0;
+    EndpointID        local_eid = BundleDaemon::instance()->local_eid();
+    BP_Local_CS*    locals;
+    bool            result = false;     //default is "no" even in case of errors
+
+    log_debug_p(log, "Ciphersuite::source_is_local_node()");
+    if ( block == NULL )
+        return false;
+        
+    if ( block->locals() == NULL )       // then the block is broken
+        return false;
+    
+    locals = dynamic_cast<BP_Local_CS*>(block->locals());
+    if ( locals == NULL )
+        return false;
+
+    cs_flags = locals->cs_flags();
+    
+    // this is a very clunky way to get the "base" portion of the bundle destination
+    std::string bundle_src_str = bundle->source().uri().scheme() + "://" +
+                                 bundle->source().uri().host();
+    EndpointID        src_node(bundle_src_str);
+    
+    
+    // if this is security-src, or there isn't one and this is bundle source
+    if (  (  (cs_flags & Ciphersuite::CS_BLOCK_HAS_SOURCE) && (local_eid == locals->security_src())) ||
+          ( !(cs_flags & Ciphersuite::CS_BLOCK_HAS_SOURCE) && (local_eid == src_node)              )    ) 
+    {  //yes - this is ours 
+        result = true;
+    }
+    
+    return result;
+}
+
+//----------------------------------------------------------------------
+bool
+Ciphersuite::check_validation(const Bundle*       bundle,
+                              const BlockInfoVec* block_list,
+                              u_int16_t           num)
+{
+    (void)bundle;
+    u_int16_t       proc_flags = 0;
+    BP_Local_CS*    locals;
+    BlockInfoVec::const_iterator iter;
+
+    log_debug_p(log, "Ciphersuite::check_validation(%hu)", num);
+    if ( block_list == NULL )
+        return false;
+        
+    for ( iter = block_list->begin();
+          iter != block_list->end();
+          ++iter)
+    {
+        if ( iter->locals() == NULL )       // then of no interest
+            continue;
+        
+        locals = dynamic_cast<BP_Local_CS*>(iter->locals());
+        if ( locals == NULL )
+            continue;
+    
+        if (locals->owner_cs_num() != num )
+            continue;
+        
+        // OK - this is one of interest
+        proc_flags |= locals->proc_flags();
+    }
+    
+    // Now check what we have collected
+    // If we positively validated, we succeeded
+    if ( proc_flags & CS_BLOCK_PASSED_VALIDATION )
+        return true;
+    
+    // If we had no positives, then any failure is failure
+    if ( proc_flags & CS_BLOCK_FAILED_VALIDATION )
+        return false;
+    
+    // If no positives but no failure, then did we have 
+    // a block which we couldn't test
+    if ( proc_flags & CS_BLOCK_DID_NOT_FAIL )
+        return true;
+    
+    return false;   // no blocks of wanted type
+}
+
+//----------------------------------------------------------------------
+u_int64_t
+Ciphersuite::create_correlator(const Bundle*       bundle,
+                               const BlockInfoVec* block_list)
+{
+    (void)bundle;
+    u_int64_t       result = 0LLU;
+    u_int16_t       high_val = 1;
+    u_int16_t       value;
+    BP_Local_CS*    locals;
+    BlockInfoVec::const_iterator iter;
+
+    log_debug_p(log, "Ciphersuite::create_correlator()");
+    if ( bundle == NULL )
+        return 1LLU;        // and good luck :)
+        
+    if ( block_list == NULL )
+        return 1LLU;
+        
+    if ( bundle->is_fragment() ) {
+        result = bundle->frag_offset() << 24;
+    }
+    
+    for ( iter = block_list->begin();
+          iter != block_list->end();
+          ++iter)
+    {
+        if ( iter->locals() == NULL )       // then of no interest
+            continue;
+        
+        locals = dynamic_cast<BP_Local_CS*>(iter->locals());
+        if ( locals == NULL )
+            continue;
+    
+        value = locals->correlator();       // only low-order 16 bits
+        
+        value = value > high_val ? value : high_val;
+    }
+    
+    result |= high_val;     // put high_val into low-order two bytes
+    
+    return result;
+}
+
+//----------------------------------------------------------------------
+void
+Ciphersuite::init_locals(BlockInfo* block)
+{
+    /* Create new locals block but do not overwrite
+     * if one already exists.
+     * Derived classes may wish to change this behavior
+     * and map old-to-new, or whatever
+     */
+     
+    if ( block->locals() == NULL )
+        block->set_locals( new BP_Local_CS );
+    
+}
+
+//----------------------------------------------------------------------
+BP_Local_CS::BP_Local_CS()
+    : BP_Local(),
+      cs_flags_(0), 
+      security_result_offset_(0), 
+      correlator_(0LL),
+      security_params_(),
+      security_result_(),
+      owner_cs_num_(0)
+{
+}
+
+//----------------------------------------------------------------------
+BP_Local_CS::BP_Local_CS(const BP_Local_CS& b)
+    : BP_Local(),
+      cs_flags_(b.cs_flags_), 
+      security_result_offset_(b.security_result_offset_), 
+      correlator_(b.correlator_),
+      security_params_(b.security_params_),
+      security_result_(b.security_result_),
+      owner_cs_num_(b.owner_cs_num_)
+    //XXX-pl  might need more items copied
+{
+}
+
+//----------------------------------------------------------------------
+BP_Local_CS::~BP_Local_CS()
+{
+}
+
+//----------------------------------------------------------------------
+void
+BP_Local_CS::set_key(u_char* k, size_t len)
+{
+    key_.reserve(len);
+    key_.set_len(len);
+    memcpy(key_.buf(), k, len);
+}
+
+//----------------------------------------------------------------------
+void
+BP_Local_CS::set_salt(u_char* s, size_t len)
+{
+    salt_.reserve(len);
+    salt_.set_len(len);
+    memcpy(salt_.buf(), s, len);
+}
+
+//----------------------------------------------------------------------
+void
+BP_Local_CS::set_iv(u_char* iv, size_t len)
+{
+    iv_.reserve(len);
+    iv_.set_len(len);
+    memcpy(iv_.buf(), iv, len);
+}
+
+
+} // namespace dtn
+
+#endif /* BSP_ENABLED */