IBR-DTNSuite  0.8
ibrdtn/ibrdtn/security/PayloadIntegrityBlock.cpp
Go to the documentation of this file.
00001 #include "ibrdtn/security/PayloadIntegrityBlock.h"
00002 #include "ibrdtn/security/MutualSerializer.h"
00003 #include "ibrdtn/data/Bundle.h"
00004 
00005 #include <ibrcommon/ssl/RSASHA256Stream.h>
00006 #include <ibrcommon/Logger.h>
00007 #include <openssl/err.h>
00008 #include <openssl/rsa.h>
00009 
00010 #ifdef __DEVELOPMENT_ASSERTIONS__
00011 #include <cassert>
00012 #endif
00013 
00014 namespace dtn
00015 {
00016         namespace security
00017         {
00018                 dtn::data::Block* PayloadIntegrityBlock::Factory::create()
00019                 {
00020                         return new PayloadIntegrityBlock();
00021                 }
00022 
00023                 PayloadIntegrityBlock::PayloadIntegrityBlock()
00024                  : SecurityBlock(PAYLOAD_INTEGRITY_BLOCK, PIB_RSA_SHA256), result_size(0)
00025                 {
00026                 }
00027 
00028                 PayloadIntegrityBlock::~PayloadIntegrityBlock()
00029                 {
00030                 }
00031 
00032                 size_t PayloadIntegrityBlock::getSecurityResultSize() const
00033                 {
00034                         if (result_size > 0)
00035                         {
00036                                 return result_size;
00037                         }
00038 
00039                         return SecurityBlock::getSecurityResultSize();
00040                 }
00041 
00042                 void PayloadIntegrityBlock::sign(dtn::data::Bundle &bundle, const SecurityKey &key, const dtn::data::EID& destination)
00043                 {
00044                         PayloadIntegrityBlock& pib = bundle.push_front<PayloadIntegrityBlock>();
00045                         pib.set(REPLICATE_IN_EVERY_FRAGMENT, true);
00046 
00047                         // check if this is a fragment
00048                         if (bundle.get(dtn::data::PrimaryBlock::FRAGMENT))
00049                         {
00050                                 dtn::data::PayloadBlock& plb = bundle.getBlock<dtn::data::PayloadBlock>();
00051                                 ibrcommon::BLOB::Reference blobref = plb.getBLOB();
00052                                 ibrcommon::BLOB::iostream stream = blobref.iostream();
00053                                 addFragmentRange(pib._ciphersuite_params, bundle._fragmentoffset, stream.size());
00054                         }
00055 
00056                         // set the source and destination address of the new block
00057                         if (key.reference != bundle._source.getNode()) pib.setSecuritySource( key.reference );
00058                         if (destination != bundle._destination.getNode()) pib.setSecurityDestination( destination );
00059 
00060                         pib.setResultSize(key);
00061                         pib.setCiphersuiteId(SecurityBlock::PIB_RSA_SHA256);
00062                         pib._ciphersuite_flags |= CONTAINS_SECURITY_RESULT;
00063                         std::string sign = calcHash(bundle, key, pib);
00064                         pib._security_result.set(SecurityBlock::integrity_signature, sign);
00065                 }
00066 
00067                 const std::string PayloadIntegrityBlock::calcHash(const dtn::data::Bundle &bundle, const SecurityKey &key, PayloadIntegrityBlock& ignore)
00068                 {
00069                         EVP_PKEY *pkey = key.getEVP();
00070                         ibrcommon::RSASHA256Stream rs2s(pkey);
00071 
00072                         // serialize the bundle in the mutable form
00073                         dtn::security::MutualSerializer ms(rs2s, &ignore);
00074                         (dtn::data::DefaultSerializer&)ms << bundle; rs2s << std::flush;
00075 
00076                         int return_code = rs2s.getSign().first;
00077                         std::string sign_string = rs2s.getSign().second;
00078                         SecurityKey::free(pkey);
00079 
00080                         if (return_code)
00081                                 return sign_string;
00082                         else
00083                         {
00084                                 IBRCOMMON_LOGGER_ex(critical) << "an error occured at the creation of the hash and it is invalid" << IBRCOMMON_LOGGER_ENDL;
00085                                 ERR_print_errors_fp(stderr);
00086                                 return std::string("");
00087                         }
00088                 }
00089 
00090                 void PayloadIntegrityBlock::verify(const dtn::data::Bundle& bundle, const SecurityKey &key, const PayloadIntegrityBlock &sb, const bool use_eid)
00091                 {
00092                         // check if we have the public key of the security source
00093                         if (use_eid)
00094                         {
00095                                 if (!sb.isSecuritySource(bundle, key.reference))
00096                                 {
00097                                         throw ibrcommon::Exception("key not match the security source");
00098                                 }
00099                         }
00100 
00101                         // check the correct algorithm
00102                         if (sb._ciphersuite_id != SecurityBlock::PIB_RSA_SHA256)
00103                         {
00104                                 throw ibrcommon::Exception("can not verify the PIB because of an invalid algorithm");
00105                         }
00106 
00107                         EVP_PKEY *pkey = key.getEVP();
00108                         if (pkey == NULL) throw ibrcommon::Exception("verification error");
00109 
00110                         ibrcommon::RSASHA256Stream rs2s(pkey, true);
00111 
00112                         // serialize the bundle in the mutable form
00113                         dtn::security::MutualSerializer ms(rs2s, &sb);
00114                         (dtn::data::DefaultSerializer&)ms << bundle; rs2s << std::flush;
00115 
00116                         int ret = rs2s.getVerification(sb._security_result.get(SecurityBlock::integrity_signature));
00117                         SecurityKey::free(pkey);
00118 
00119                         if (ret == 0)
00120                         {
00121                                 throw ibrcommon::Exception("verification failed");
00122                         }
00123                         else if (ret < 0)
00124                         {
00125                                 throw ibrcommon::Exception("verification error");
00126                         }
00127                 }
00128 
00129                 void PayloadIntegrityBlock::verify(const dtn::data::Bundle &bundle, const SecurityKey &key)
00130                 {
00131                         // iterate over all PIBs to find the right one
00132                         std::list<const PayloadIntegrityBlock *> pibs = bundle.getBlocks<PayloadIntegrityBlock>();
00133 
00134                         for (std::list<const PayloadIntegrityBlock *>::const_iterator it = pibs.begin(); it!=pibs.end(); it++)
00135                         {
00136                                 verify(bundle, key, **it);
00137                         }
00138                 }
00139 
00140                 void PayloadIntegrityBlock::setResultSize(const SecurityKey &key)
00141                 {
00142                         EVP_PKEY *pkey = key.getEVP();
00143 
00144                         // size of integrity_signature
00145                         if ((result_size = EVP_PKEY_size(pkey)) > 0)
00146                         {
00147                                 // sdnv length
00148                                 result_size += dtn::data::SDNV(result_size).getLength();
00149 
00150                                 // type
00151                                 result_size++;
00152                         }
00153                         else
00154                         {
00155                                 result_size = _security_result.getLength();
00156                         }
00157 
00158                         SecurityKey::free(pkey);
00159                 }
00160 
00161                 void PayloadIntegrityBlock::strip(dtn::data::Bundle& bundle, const SecurityKey &key, const bool all)
00162                 {
00163                         std::list<const PayloadIntegrityBlock *> pibs = bundle.getBlocks<PayloadIntegrityBlock>();
00164                         const PayloadIntegrityBlock * valid = NULL;
00165 
00166                         // search for valid PIB
00167                         for (std::list<const PayloadIntegrityBlock *>::const_iterator it = pibs.begin(); it != pibs.end() && !valid; it++)
00168                         {
00169                                 const PayloadIntegrityBlock &pib = (**it);
00170 
00171                                 // check if the PIB is valid
00172                                 try {
00173                                         verify(bundle, key, pib);
00174 
00175                                         // found an valid PIB, remove it
00176                                         bundle.remove(pib);
00177 
00178                                         // remove all previous pibs if all = true
00179                                         if (all && (it != pibs.begin()))
00180                                         {
00181                                                 // move the iterator one backward
00182                                                 for (it--; it != pibs.begin(); it--)
00183                                                 {
00184                                                         bundle.remove(**it);
00185                                                 }
00186 
00187                                                 // remove the first PIB too
00188                                                 bundle.remove(**it);
00189                                         }
00190 
00191                                         return;
00192                                 } catch (const ibrcommon::Exception&) { };
00193                         }
00194                 }
00195 
00196                 void PayloadIntegrityBlock::strip(dtn::data::Bundle& bundle)
00197                 {
00198                         std::list<const PayloadIntegrityBlock *> pibs = bundle.getBlocks<PayloadIntegrityBlock>();
00199                         for (std::list<const PayloadIntegrityBlock *>::const_iterator it = pibs.begin(); it != pibs.end(); it++)
00200                         {
00201                                 bundle.remove(*(*it));
00202                         }
00203                 }
00204 
00205                 std::istream& PayloadIntegrityBlock::deserialize(std::istream &stream, const size_t length)
00206                 {
00207                         // deserialize the SecurityBlock
00208                         SecurityBlock::deserialize(stream, length);
00209 
00210                         // set the key size locally
00211                         result_size = _security_result.getLength();
00212 
00213                         return stream;
00214                 }
00215         }
00216 }