servlib/security/Ciphersuite.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2006 SPARTA Inc
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #ifdef HAVE_CONFIG_H
       
    18 #  include <dtn-config.h>
       
    19 #endif
       
    20 
       
    21 #ifdef BSP_ENABLED
       
    22 
       
    23 #include "Ciphersuite.h"
       
    24 #include "BA_BlockProcessor.h"
       
    25 #include "Ciphersuite_BA1.h"
       
    26 #include "PI_BlockProcessor.h"
       
    27 #include "Ciphersuite_PI2.h"
       
    28 #include "PC_BlockProcessor.h"
       
    29 #include "Ciphersuite_PC3.h"
       
    30 #include "bundling/Bundle.h"
       
    31 #include "bundling/BundleDaemon.h"
       
    32 #include "bundling/BundleProtocol.h"
       
    33 #include "contacts/Link.h"
       
    34 #include "bundling/SDNV.h"
       
    35 
       
    36 namespace dtn {
       
    37 
       
    38 
       
    39 #define CS_MAX 1024
       
    40 Ciphersuite* Ciphersuite::ciphersuites_[CS_MAX];
       
    41 
       
    42 static const char* log = "/dtn/bundle/ciphersuite";
       
    43 
       
    44 bool Ciphersuite::inited = false;
       
    45 
       
    46 //----------------------------------------------------------------------
       
    47 Ciphersuite::Ciphersuite()
       
    48 //    : BlockProcessor(block_type)
       
    49 {
       
    50     log_debug_p(log, "Ciphersuite::Ciphersuite()");
       
    51 }
       
    52 
       
    53 //----------------------------------------------------------------------
       
    54 Ciphersuite::~Ciphersuite()
       
    55 { }
       
    56 
       
    57 //----------------------------------------------------------------------
       
    58 void
       
    59 Ciphersuite::register_ciphersuite(Ciphersuite* cs)
       
    60 {
       
    61     log_debug_p(log, "Ciphersuite::register_ciphersuite()");
       
    62     u_int16_t    num = cs->cs_num();
       
    63     
       
    64     if ( num <= 0 || num >= CS_MAX )
       
    65         return;            //out of range
       
    66         
       
    67     // don't override an existing suite
       
    68     ASSERT(ciphersuites_[num] == 0);
       
    69     ciphersuites_[num] = cs;
       
    70 }
       
    71 
       
    72 //----------------------------------------------------------------------
       
    73 Ciphersuite*
       
    74 Ciphersuite::find_suite(u_int16_t num)
       
    75 {
       
    76     Ciphersuite* ret = NULL;
       
    77     log_debug_p(log, "Ciphersuite::find_suite()");
       
    78     
       
    79     if ( num > 0 && num < CS_MAX )  // entry for element zero is illegal
       
    80         ret = ciphersuites_[num];
       
    81 
       
    82     return ret;
       
    83 }
       
    84 
       
    85 //----------------------------------------------------------------------
       
    86 void
       
    87 Ciphersuite::init_default_ciphersuites()
       
    88 {
       
    89     log_debug_p(log, "Ciphersuite::init_default_ciphersuites()");
       
    90     if ( ! inited ) {
       
    91         // register default block processor handlers
       
    92         BundleProtocol::register_processor(new BA_BlockProcessor());
       
    93         BundleProtocol::register_processor(new PI_BlockProcessor());
       
    94         BundleProtocol::register_processor(new PC_BlockProcessor());
       
    95         
       
    96         // register mandatory ciphersuites
       
    97         register_ciphersuite(new Ciphersuite_BA1());
       
    98         register_ciphersuite(new Ciphersuite_PI2());
       
    99         register_ciphersuite(new Ciphersuite_PC3());
       
   100         
       
   101         inited = true;
       
   102     }
       
   103 }
       
   104 
       
   105 //----------------------------------------------------------------------
       
   106 u_int16_t
       
   107 Ciphersuite::cs_num(void)
       
   108 {
       
   109 
       
   110     return 0;
       
   111 }
       
   112 
       
   113 //----------------------------------------------------------------------
       
   114 void
       
   115 Ciphersuite::parse(BlockInfo* block)
       
   116 {
       
   117     Ciphersuite*    cs_owner = NULL;
       
   118     BP_Local_CS*    locals = NULL;
       
   119     u_char*         buf;
       
   120     size_t          len;
       
   121     u_int64_t       cs_flags;
       
   122     u_int64_t       suite_num;
       
   123     int             sdnv_len;
       
   124     u_int64_t       security_correlator    = 0LL;
       
   125     u_int64_t       field_length           = 0LL;
       
   126     bool            has_source;    
       
   127     bool            has_dest;      
       
   128     bool            has_params;    
       
   129     bool            has_correlator;
       
   130     bool            has_result;   
       
   131     EndpointIDVector::const_iterator iter;
       
   132     
       
   133 // XXX/pl todo  think about a "const" version of parse() since there
       
   134 //              are several callers who need parsing but have a const block
       
   135     
       
   136     log_debug_p(log, "Ciphersuite::parse() block %p", block);
       
   137     ASSERT(block != NULL);
       
   138     
       
   139     // preamble has already been parsed and stored, so we skip over it here
       
   140 //get the type
       
   141 //get flags sdnv
       
   142 //get length sdnv
       
   143     
       
   144     buf = block->contents().buf() + block->data_offset();
       
   145     len = block->data_length();
       
   146     
       
   147 //get ciphersuite and flags
       
   148     sdnv_len = SDNV::decode(buf,
       
   149                             len,
       
   150                             &suite_num);
       
   151     buf += sdnv_len;
       
   152     len -= sdnv_len;
       
   153 
       
   154     sdnv_len = SDNV::decode(buf,
       
   155                             len,
       
   156                             &cs_flags);
       
   157     buf += sdnv_len;
       
   158     len -= sdnv_len;
       
   159 
       
   160     has_source     = (cs_flags & CS_BLOCK_HAS_SOURCE)     != 0;
       
   161     has_dest       = (cs_flags & CS_BLOCK_HAS_DEST)       != 0;
       
   162     has_params     = (cs_flags & CS_BLOCK_HAS_PARAMS)     != 0;
       
   163     has_correlator = (cs_flags & CS_BLOCK_HAS_CORRELATOR) != 0;
       
   164     has_result     = (cs_flags & CS_BLOCK_HAS_RESULT)     != 0;
       
   165     log_debug_p(log, "Ciphersuite::parse() suite_num %llu cs_flags 0x%llx",
       
   166                 U64FMT(suite_num), U64FMT(cs_flags));
       
   167     
       
   168     cs_owner = dynamic_cast<Ciphersuite*>(find_suite(suite_num));
       
   169     
       
   170     if ( ciphersuites_[suite_num] != NULL )            // get specific subclass if it's present
       
   171         cs_owner = ciphersuites_[suite_num];
       
   172     
       
   173     if ( block->locals() == NULL ) {
       
   174         if ( cs_owner != NULL )
       
   175             cs_owner->init_locals(block);                // get owning class to allocate locals
       
   176         else
       
   177             block->set_locals( new BP_Local_CS );
       
   178     }
       
   179     
       
   180     locals = dynamic_cast<BP_Local_CS*>(block->locals());
       
   181     ASSERT ( locals != NULL );
       
   182 
       
   183     ASSERT ( suite_num < 65535 );
       
   184     locals->set_owner_cs_num(suite_num);
       
   185 
       
   186 //set cs_flags
       
   187     ASSERT ( cs_flags  < 65535  );
       
   188     locals->set_cs_flags(cs_flags);
       
   189     
       
   190 //get correlator, if present
       
   191     if ( has_correlator ) {    
       
   192         sdnv_len = SDNV::decode(buf,
       
   193                                 len,
       
   194                                 &security_correlator);
       
   195         buf += sdnv_len;
       
   196         len -= sdnv_len;
       
   197     }
       
   198     log_debug_p(log, "Ciphersuite::parse() correlator %llu",
       
   199                 U64FMT(security_correlator));
       
   200     locals->set_correlator(security_correlator);
       
   201     
       
   202 
       
   203 //get cs params length, and data
       
   204     if ( has_params ) {    
       
   205         sdnv_len = SDNV::decode(buf,
       
   206                                 len,
       
   207                                 &field_length);
       
   208         buf += sdnv_len;
       
   209         len -= sdnv_len;
       
   210         // make sure the buffer has enough space, copy data in
       
   211         locals->writable_security_params()->reserve(field_length);
       
   212         memcpy( locals->writable_security_params()->end(), buf, field_length);
       
   213         locals->writable_security_params()->set_len(field_length);
       
   214         buf += field_length;
       
   215         len -= field_length;
       
   216         log_debug_p(log, "Ciphersuite::parse() security_params len %llu",
       
   217                     U64FMT(field_length));
       
   218     }
       
   219     
       
   220 
       
   221 //get sec-src length and data
       
   222     log_debug_p(log, "Ciphersuite::parse() eid_list().size() %zu has_source %u has_dest %u", 
       
   223                 block->eid_list().size(), has_source, has_dest);
       
   224     
       
   225     // XXX/pl - temp fix for blocks loaded from store
       
   226     if ( block->eid_list().size() > 0 ) {
       
   227         iter = block->eid_list().begin();
       
   228         if ( has_source ) {    
       
   229             locals->set_security_src( iter->str() );
       
   230             iter++;
       
   231         }
       
   232         
       
   233 
       
   234         //get sec-dest length and data
       
   235         if ( has_dest ) {    
       
   236             locals->set_security_dest( iter->str() );
       
   237         }
       
   238     }
       
   239     
       
   240 
       
   241  //get sec-result length and data, if present
       
   242     if ( has_result ) {    
       
   243         sdnv_len = SDNV::decode(buf,
       
   244                                 len,
       
   245                                 &field_length);
       
   246         buf += sdnv_len;
       
   247         len -= sdnv_len;
       
   248         // make sure the buffer has enough space, copy data in
       
   249         locals->writable_security_result()->reserve(field_length);
       
   250         memcpy( locals->writable_security_result()->end(), buf, field_length);
       
   251         locals->writable_security_result()->set_len(field_length);
       
   252         buf += field_length;
       
   253         len -= field_length;
       
   254         
       
   255     }
       
   256     
       
   257 
       
   258 
       
   259 
       
   260 }
       
   261 
       
   262 
       
   263 //----------------------------------------------------------------------
       
   264 int
       
   265 Ciphersuite::reload_post_process(Bundle*       bundle,
       
   266                                  BlockInfoVec* block_list,
       
   267                                  BlockInfo*    block)
       
   268 {
       
   269     (void)bundle;
       
   270     (void)block_list;
       
   271     (void)block;
       
   272     
       
   273     // Received blocks might be stored and reloaded and
       
   274     // some fields aren't reset.
       
   275     // This allows BlockProcessors to reestablish what they
       
   276     // need. The default implementation does nothing.
       
   277     // In general that's appropriate, as the BlockProcessor
       
   278     // will have called parse() and that's the main need. 
       
   279     // Individual ciphersuites can override this if their 
       
   280     // usage requires it.
       
   281     
       
   282     block->set_reloaded(false);
       
   283     return 0;
       
   284 
       
   285 }
       
   286 
       
   287 //----------------------------------------------------------------------
       
   288 void
       
   289 Ciphersuite::generate_preamble(BlockInfoVec* xmit_blocks,
       
   290                                BlockInfo*    block,
       
   291                                u_int8_t      type,
       
   292                                u_int64_t     flags,
       
   293                                u_int64_t     data_length)
       
   294 {
       
   295     block->owner()->generate_preamble(xmit_blocks, block, type,
       
   296                                       flags, data_length);
       
   297 }
       
   298 
       
   299 //----------------------------------------------------------------------
       
   300 bool
       
   301 Ciphersuite::destination_is_local_node(const Bundle*    bundle,
       
   302                                        const BlockInfo* block)
       
   303 {
       
   304     u_int16_t       cs_flags = 0;
       
   305     EndpointID        local_eid = BundleDaemon::instance()->local_eid();
       
   306     BP_Local_CS*    locals;
       
   307     bool            result = false;     //default is "no" even in case of errors
       
   308 
       
   309     log_debug_p(log, "Ciphersuite::destination_is_local_node()");
       
   310     if ( block == NULL )
       
   311         return false;
       
   312         
       
   313     if ( block->locals() == NULL )       // then the block is broken
       
   314         return false;
       
   315     
       
   316     locals = dynamic_cast<BP_Local_CS*>(block->locals());
       
   317     if ( locals == NULL )
       
   318         return false;
       
   319 
       
   320     cs_flags = locals->cs_flags();
       
   321     
       
   322     // this is a very clunky way to get the "base" portion of the bundle destination
       
   323     std::string bundle_dest_str = bundle->dest().uri().scheme() + "://" +
       
   324                                   bundle->dest().uri().host();
       
   325     EndpointID        dest_node(bundle_dest_str);
       
   326     
       
   327     
       
   328     // if this is security-dest, or there isn't one and this is bundle dest
       
   329     if (  (  (cs_flags & Ciphersuite::CS_BLOCK_HAS_DEST) && (local_eid == locals->security_dest())) ||
       
   330           ( !(cs_flags & Ciphersuite::CS_BLOCK_HAS_DEST) && (local_eid == dest_node)              )    ) 
       
   331     {  //yes - this is ours 
       
   332         result = true;
       
   333     }
       
   334     
       
   335     return result;
       
   336 }
       
   337 
       
   338 //----------------------------------------------------------------------
       
   339 bool
       
   340 Ciphersuite::source_is_local_node(const Bundle* bundle, const BlockInfo* block)
       
   341 {
       
   342     u_int16_t       cs_flags = 0;
       
   343     EndpointID        local_eid = BundleDaemon::instance()->local_eid();
       
   344     BP_Local_CS*    locals;
       
   345     bool            result = false;     //default is "no" even in case of errors
       
   346 
       
   347     log_debug_p(log, "Ciphersuite::source_is_local_node()");
       
   348     if ( block == NULL )
       
   349         return false;
       
   350         
       
   351     if ( block->locals() == NULL )       // then the block is broken
       
   352         return false;
       
   353     
       
   354     locals = dynamic_cast<BP_Local_CS*>(block->locals());
       
   355     if ( locals == NULL )
       
   356         return false;
       
   357 
       
   358     cs_flags = locals->cs_flags();
       
   359     
       
   360     // this is a very clunky way to get the "base" portion of the bundle destination
       
   361     std::string bundle_src_str = bundle->source().uri().scheme() + "://" +
       
   362                                  bundle->source().uri().host();
       
   363     EndpointID        src_node(bundle_src_str);
       
   364     
       
   365     
       
   366     // if this is security-src, or there isn't one and this is bundle source
       
   367     if (  (  (cs_flags & Ciphersuite::CS_BLOCK_HAS_SOURCE) && (local_eid == locals->security_src())) ||
       
   368           ( !(cs_flags & Ciphersuite::CS_BLOCK_HAS_SOURCE) && (local_eid == src_node)              )    ) 
       
   369     {  //yes - this is ours 
       
   370         result = true;
       
   371     }
       
   372     
       
   373     return result;
       
   374 }
       
   375 
       
   376 //----------------------------------------------------------------------
       
   377 bool
       
   378 Ciphersuite::check_validation(const Bundle*       bundle,
       
   379                               const BlockInfoVec* block_list,
       
   380                               u_int16_t           num)
       
   381 {
       
   382     (void)bundle;
       
   383     u_int16_t       proc_flags = 0;
       
   384     BP_Local_CS*    locals;
       
   385     BlockInfoVec::const_iterator iter;
       
   386 
       
   387     log_debug_p(log, "Ciphersuite::check_validation(%hu)", num);
       
   388     if ( block_list == NULL )
       
   389         return false;
       
   390         
       
   391     for ( iter = block_list->begin();
       
   392           iter != block_list->end();
       
   393           ++iter)
       
   394     {
       
   395         if ( iter->locals() == NULL )       // then of no interest
       
   396             continue;
       
   397         
       
   398         locals = dynamic_cast<BP_Local_CS*>(iter->locals());
       
   399         if ( locals == NULL )
       
   400             continue;
       
   401     
       
   402         if (locals->owner_cs_num() != num )
       
   403             continue;
       
   404         
       
   405         // OK - this is one of interest
       
   406         proc_flags |= locals->proc_flags();
       
   407     }
       
   408     
       
   409     // Now check what we have collected
       
   410     // If we positively validated, we succeeded
       
   411     if ( proc_flags & CS_BLOCK_PASSED_VALIDATION )
       
   412         return true;
       
   413     
       
   414     // If we had no positives, then any failure is failure
       
   415     if ( proc_flags & CS_BLOCK_FAILED_VALIDATION )
       
   416         return false;
       
   417     
       
   418     // If no positives but no failure, then did we have 
       
   419     // a block which we couldn't test
       
   420     if ( proc_flags & CS_BLOCK_DID_NOT_FAIL )
       
   421         return true;
       
   422     
       
   423     return false;   // no blocks of wanted type
       
   424 }
       
   425 
       
   426 //----------------------------------------------------------------------
       
   427 u_int64_t
       
   428 Ciphersuite::create_correlator(const Bundle*       bundle,
       
   429                                const BlockInfoVec* block_list)
       
   430 {
       
   431     (void)bundle;
       
   432     u_int64_t       result = 0LLU;
       
   433     u_int16_t       high_val = 1;
       
   434     u_int16_t       value;
       
   435     BP_Local_CS*    locals;
       
   436     BlockInfoVec::const_iterator iter;
       
   437 
       
   438     log_debug_p(log, "Ciphersuite::create_correlator()");
       
   439     if ( bundle == NULL )
       
   440         return 1LLU;        // and good luck :)
       
   441         
       
   442     if ( block_list == NULL )
       
   443         return 1LLU;
       
   444         
       
   445     if ( bundle->is_fragment() ) {
       
   446         result = bundle->frag_offset() << 24;
       
   447     }
       
   448     
       
   449     for ( iter = block_list->begin();
       
   450           iter != block_list->end();
       
   451           ++iter)
       
   452     {
       
   453         if ( iter->locals() == NULL )       // then of no interest
       
   454             continue;
       
   455         
       
   456         locals = dynamic_cast<BP_Local_CS*>(iter->locals());
       
   457         if ( locals == NULL )
       
   458             continue;
       
   459     
       
   460         value = locals->correlator();       // only low-order 16 bits
       
   461         
       
   462         value = value > high_val ? value : high_val;
       
   463     }
       
   464     
       
   465     result |= high_val;     // put high_val into low-order two bytes
       
   466     
       
   467     return result;
       
   468 }
       
   469 
       
   470 //----------------------------------------------------------------------
       
   471 void
       
   472 Ciphersuite::init_locals(BlockInfo* block)
       
   473 {
       
   474     /* Create new locals block but do not overwrite
       
   475      * if one already exists.
       
   476      * Derived classes may wish to change this behavior
       
   477      * and map old-to-new, or whatever
       
   478      */
       
   479      
       
   480     if ( block->locals() == NULL )
       
   481         block->set_locals( new BP_Local_CS );
       
   482     
       
   483 }
       
   484 
       
   485 //----------------------------------------------------------------------
       
   486 BP_Local_CS::BP_Local_CS()
       
   487     : BP_Local(),
       
   488       cs_flags_(0), 
       
   489       security_result_offset_(0), 
       
   490       correlator_(0LL),
       
   491       security_params_(),
       
   492       security_result_(),
       
   493       owner_cs_num_(0)
       
   494 {
       
   495 }
       
   496 
       
   497 //----------------------------------------------------------------------
       
   498 BP_Local_CS::BP_Local_CS(const BP_Local_CS& b)
       
   499     : BP_Local(),
       
   500       cs_flags_(b.cs_flags_), 
       
   501       security_result_offset_(b.security_result_offset_), 
       
   502       correlator_(b.correlator_),
       
   503       security_params_(b.security_params_),
       
   504       security_result_(b.security_result_),
       
   505       owner_cs_num_(b.owner_cs_num_)
       
   506     //XXX-pl  might need more items copied
       
   507 {
       
   508 }
       
   509 
       
   510 //----------------------------------------------------------------------
       
   511 BP_Local_CS::~BP_Local_CS()
       
   512 {
       
   513 }
       
   514 
       
   515 //----------------------------------------------------------------------
       
   516 void
       
   517 BP_Local_CS::set_key(u_char* k, size_t len)
       
   518 {
       
   519     key_.reserve(len);
       
   520     key_.set_len(len);
       
   521     memcpy(key_.buf(), k, len);
       
   522 }
       
   523 
       
   524 //----------------------------------------------------------------------
       
   525 void
       
   526 BP_Local_CS::set_salt(u_char* s, size_t len)
       
   527 {
       
   528     salt_.reserve(len);
       
   529     salt_.set_len(len);
       
   530     memcpy(salt_.buf(), s, len);
       
   531 }
       
   532 
       
   533 //----------------------------------------------------------------------
       
   534 void
       
   535 BP_Local_CS::set_iv(u_char* iv, size_t len)
       
   536 {
       
   537     iv_.reserve(len);
       
   538     iv_.set_len(len);
       
   539     memcpy(iv_.buf(), iv, len);
       
   540 }
       
   541 
       
   542 
       
   543 } // namespace dtn
       
   544 
       
   545 #endif /* BSP_ENABLED */