void SecurityManager::fastverify(const dtn::data::Bundle &bundle) const throw (VerificationFailedException) { // do a fast verify without manipulating the bundle const dtn::daemon::Configuration::Security &secconf = dtn::daemon::Configuration::getInstance().getSecurity(); if (secconf.getLevel() & dtn::daemon::Configuration::Security::SECURITY_LEVEL_ENCRYPTED) { // check if the bundle is encrypted and throw an exception if not //throw VerificationFailedException("Bundle is not encrypted"); IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "encryption required, verify bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; if (std::count(bundle.begin(), bundle.end(), dtn::security::PayloadConfidentialBlock::BLOCK_TYPE) == 0) throw VerificationFailedException("No PCB available!"); } if (secconf.getLevel() & dtn::daemon::Configuration::Security::SECURITY_LEVEL_SIGNED) { // check if the bundle is signed and throw an exception if not //throw VerificationFailedException("Bundle is not signed"); IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "signature required, verify bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; if (std::count(bundle.begin(), bundle.end(), dtn::security::PayloadIntegrityBlock::BLOCK_TYPE) == 0) throw VerificationFailedException("No PIB available!"); } if (secconf.getLevel() & dtn::daemon::Configuration::Security::SECURITY_LEVEL_AUTHENTICATED) { // check if the bundle is signed and throw an exception if not //throw VerificationFailedException("Bundle is not signed"); IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "authentication required, verify bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; if (std::count(bundle.begin(), bundle.end(), dtn::security::BundleAuthenticationBlock::BLOCK_TYPE) == 0) throw VerificationFailedException("No BAB available!"); } }
bool DefaultSerializer::isCompressable(const dtn::data::Bundle &obj) const { // check if all EID are compressable bool compressable = ( obj.source.isCompressable() && obj.destination.isCompressable() && obj.reportto.isCompressable() && obj.custodian.isCompressable() ); if (compressable) { // add EID of all secondary blocks for (Bundle::const_iterator iter = obj.begin(); iter != obj.end(); ++iter) { const Block &b = (**iter); const std::list<dtn::data::EID> eids = b.getEIDList(); for (std::list<dtn::data::EID>::const_iterator eit = eids.begin(); eit != eids.end(); ++eit) { const dtn::data::EID &eid = (*eit); if (!eid.isCompressable()) { return false; } } } } return compressable; }
void SecurityManager::verifyBAB(dtn::data::Bundle &bundle) const throw (VerificationFailedException) { IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "verify authenticated bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; // iterate over all BABs of this bundle dtn::data::Bundle::find_iterator it(bundle.begin(), dtn::security::BundleAuthenticationBlock::BLOCK_TYPE); while (it.next(bundle.end())) { const dtn::security::BundleAuthenticationBlock& bab = dynamic_cast<const dtn::security::BundleAuthenticationBlock&>(**it); // look for the right BAB-factory const dtn::data::EID node = bab.getSecuritySource(bundle); try { // try to load the key of the BAB const SecurityKey key = SecurityKeyManager::getInstance().get(node, SecurityKey::KEY_SHARED); // verify the bundle dtn::security::BundleAuthenticationBlock::verify(bundle, key); // strip all BAB of this bundle dtn::security::BundleAuthenticationBlock::strip(bundle); // set the verify bit, after verification bundle.set(dtn::data::Bundle::DTNSEC_STATUS_AUTHENTICATED, true); // at least one BAB has been authenticated, we're done! break; } catch (const SecurityKey::KeyNotFoundException&) { // no key for this node found } } }
void ExtensionSecurityBlock::decrypt(dtn::data::Bundle& bundle, const SecurityKey &key, const dtn::data::Number &correlator) { // iterate through all extension security blocks dtn::data::Bundle::find_iterator find_it(bundle.begin(), ExtensionSecurityBlock::BLOCK_TYPE); while (find_it.next(bundle.end())) { const dtn::security::ExtensionSecurityBlock &esb = dynamic_cast<const dtn::security::ExtensionSecurityBlock&>(**find_it); if ((correlator == 0) || (correlator == esb._correlator)) { decrypt(bundle, key, find_it); } } }
void PayloadIntegrityBlock::verify(const dtn::data::Bundle &bundle, const SecurityKey &key) { // iterate over all PIBs to find the right one dtn::data::Bundle::const_find_iterator it(bundle.begin(), PayloadIntegrityBlock::BLOCK_TYPE); while (it.next(bundle.end())) { const PayloadIntegrityBlock &sb = dynamic_cast<const PayloadIntegrityBlock&>(**it); // check if we have the public key of the security source // skip this block if the given key isn't the right one if (!sb.isSecuritySource(bundle, key.reference)) continue; // check the correct algorithm if (sb._ciphersuite_id != SecurityBlock::PIB_RSA_SHA256) { throw VerificationFailedException("can not verify the PIB because of an invalid algorithm"); } EVP_PKEY *pkey = key.getEVP(); if (pkey == NULL) throw VerificationFailedException("verification error"); ibrcommon::RSASHA256Stream rs2s(pkey, true); // serialize the bundle in the mutable form dtn::security::MutableSerializer ms(rs2s, &sb); (dtn::data::DefaultSerializer&)ms << bundle; rs2s << std::flush; try { int ret = rs2s.getVerification(sb._security_result.get(SecurityBlock::integrity_signature)); SecurityKey::free(pkey); if (ret > 0) { // success! return; } else if (ret < 0) { throw VerificationFailedException("verification error"); } } catch (const ElementMissingException&) { // This PIB can not verified due to a missing integrity signature throw VerificationFailedException("Integrity signature is missing!"); } } throw VerificationFailedException("verification failed"); }
void SecurityManager::verifyPIB(dtn::data::Bundle &bundle) const throw (VerificationFailedException) { IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "verify signed bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; // iterate through all blocks for (dtn::data::Bundle::iterator it = bundle.begin(); it != bundle.end();) { const dtn::data::Block &block = (**it); if (block.getType() == dtn::security::PayloadConfidentialBlock::BLOCK_TYPE) { // payload after a PCB can not verified until the payload is decrypted break; } try { const dtn::security::PayloadIntegrityBlock& pib = dynamic_cast<const dtn::security::PayloadIntegrityBlock&>(block); const SecurityKey key = SecurityKeyManager::getInstance().get(pib.getSecuritySource(bundle), SecurityKey::KEY_PUBLIC); // try to verify the bundle with the key for the current PIB dtn::security::PayloadIntegrityBlock::verify(bundle, key); // if we are the security destination if (pib.isSecurityDestination(bundle, dtn::core::BundleCore::local)) { // remove the valid PIB bundle.erase(it++); } else { ++it; } // set the verify bit, after verification bundle.set(dtn::data::PrimaryBlock::DTNSEC_STATUS_VERIFIED, true); IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 5) << "Bundle " << bundle.toString() << " successfully verified" << IBRCOMMON_LOGGER_ENDL; continue; } catch (const dtn::security::VerificationSkippedException&) { // un-set the verify bit bundle.set(dtn::data::PrimaryBlock::DTNSEC_STATUS_VERIFIED, false); } catch (const SecurityKey::KeyNotFoundException&) { // un-set the verify bit bundle.set(dtn::data::PrimaryBlock::DTNSEC_STATUS_VERIFIED, false); } catch (const std::bad_cast&) { // current block is not a PIB } ++it; } }
Length DefaultSerializer::getLength(const dtn::data::Bundle &obj) { // rebuild the dictionary rebuildDictionary(obj); Length len = 0; len += getLength( (PrimaryBlock&)obj ); // add size of all blocks for (Bundle::const_iterator iter = obj.begin(); iter != obj.end(); ++iter) { const Block &b = (**iter); len += getLength( b ); } return len; }
void BundleAuthenticationBlock::verify(const dtn::data::Bundle& bundle, const dtn::security::SecurityKey &key, dtn::data::Number &correlator) throw (ibrcommon::Exception) { // get the blocks, with which the key should match std::set<dtn::data::Number> correlators; // calculate the MAC of this bundle std::string our_hash_string = calcMAC(bundle, key); dtn::data::Bundle::const_find_iterator it(bundle.begin(), BundleAuthenticationBlock::BLOCK_TYPE); while (it.next(bundle.end())) { const BundleAuthenticationBlock &bab = dynamic_cast<const BundleAuthenticationBlock&>(**it); // the bab contains a security result if (bab._ciphersuite_flags & CONTAINS_SECURITY_RESULT) { // is this correlator known? if (correlators.find(bab._correlator) == correlators.end()) continue; std::string bab_result = bab._security_result.get(SecurityBlock::integrity_signature); if (our_hash_string == bab_result) { // hash matched correlator = bab._correlator; return; } IBRCOMMON_LOGGER_DEBUG_TAG("BundleAuthenticationBlock", 15) << "security mac does not match" << IBRCOMMON_LOGGER_ENDL; } // bab contains no security result but a correlator else if (bab._ciphersuite_flags & CONTAINS_CORRELATOR) { // currently we only support BAB_HMAC mechanism if (bab._ciphersuite_id != SecurityBlock::BAB_HMAC) continue; // skip this BAB if the security source do not match the key if (!bab.isSecuritySource(bundle, key.reference)) continue; // remember it for later check correlators.insert(bab._correlator); } } throw ibrcommon::Exception("verification failed"); }
void SecurityManager::decrypt(dtn::data::Bundle &bundle) const throw (DecryptException, KeyMissingException) { // check if the bundle has to be decrypted, return when not if (std::count(bundle.begin(), bundle.end(), dtn::security::PayloadConfidentialBlock::BLOCK_TYPE) <= 0) return; // decrypt try { IBRCOMMON_LOGGER_DEBUG_TAG("SecurityManager", 10) << "decrypt bundle: " << bundle.toString() << IBRCOMMON_LOGGER_ENDL; // get the encryption key dtn::security::SecurityKey key = SecurityKeyManager::getInstance().get(dtn::core::BundleCore::local, dtn::security::SecurityKey::KEY_PRIVATE); // encrypt the payload of the bundle dtn::security::PayloadConfidentialBlock::decrypt(bundle, key); bundle.set(dtn::data::Bundle::DTNSEC_STATUS_CONFIDENTIAL, true); } catch (const ibrcommon::Exception &ex) { throw DecryptException(ex.what()); } }
void BundleAuthenticationBlock::strip(dtn::data::Bundle &bundle, const dtn::security::SecurityKey &key) { // store the correlator of the verified BABs dtn::data::Number correlator; // verify the babs of the bundle verify(bundle, key, correlator); // iterate over all BABs dtn::data::Bundle::find_iterator it(bundle.begin(), BundleAuthenticationBlock::BLOCK_TYPE); while (it.next(bundle.end())) { const BundleAuthenticationBlock &bab = dynamic_cast<const BundleAuthenticationBlock&>(**it); // if the correlator is already authenticated, then remove the BAB if ((bab._ciphersuite_flags & SecurityBlock::CONTAINS_CORRELATOR) && (bab._correlator == correlator)) { bundle.erase(it); } } }
void BundleAuthenticationBlock::strip(dtn::data::Bundle& bundle) { bundle.erase(std::remove(bundle.begin(), bundle.end(), BundleAuthenticationBlock::BLOCK_TYPE), bundle.end()); }
void PayloadIntegrityBlock::strip(dtn::data::Bundle& bundle) { bundle.erase(std::remove(bundle.begin(), bundle.end(), PayloadIntegrityBlock::BLOCK_TYPE), bundle.end()); }
void PayloadConfidentialBlock::encrypt(dtn::data::Bundle& bundle, const dtn::security::SecurityKey &long_key, const dtn::data::EID& source) { // contains the random salt uint32_t salt; // contains the random key unsigned char ephemeral_key[ibrcommon::AES128Stream::key_size_in_bytes]; unsigned char iv[ibrcommon::AES128Stream::iv_len]; unsigned char tag[ibrcommon::AES128Stream::tag_len]; // create a new correlator value dtn::data::Number correlator = createCorrelatorValue(bundle); // create a random salt and key createSaltAndKey(salt, ephemeral_key, ibrcommon::AES128Stream::key_size_in_bytes); // count all PCBs dtn::data::Size pcbs_size = std::count(bundle.begin(), bundle.end(), PayloadConfidentialBlock::BLOCK_TYPE); // count all PIBs dtn::data::Size pibs_size = std::count(bundle.begin(), bundle.end(), PayloadIntegrityBlock::BLOCK_TYPE); // encrypt PCBs and PIBs dtn::data::Bundle::find_iterator find_pcb(bundle.begin(), PayloadConfidentialBlock::BLOCK_TYPE); while (find_pcb.next(bundle.end())) { SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, find_pcb, salt, ephemeral_key).setCorrelator(correlator); } dtn::data::Bundle::find_iterator find_pib(bundle.begin(), PayloadIntegrityBlock::BLOCK_TYPE); while (find_pib.next(bundle.end())) { SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, find_pib, salt, ephemeral_key).setCorrelator(correlator); } // create a new payload confidential block PayloadConfidentialBlock& pcb = bundle.push_front<PayloadConfidentialBlock>(); // set the correlator if (pcbs_size > 0 || pibs_size > 0) pcb.setCorrelator(correlator); // get reference to the payload block dtn::data::PayloadBlock& plb = bundle.find<dtn::data::PayloadBlock>(); ibrcommon::BLOB::Reference blobref = plb.getBLOB(); // encrypt payload - BEGIN { ibrcommon::BLOB::iostream stream = blobref.iostream(); ibrcommon::AES128Stream aes_stream(ibrcommon::CipherStream::CIPHER_ENCRYPT, *stream, ephemeral_key, salt); // encrypt in place ((ibrcommon::CipherStream&)aes_stream).encrypt(*stream); // check if this is a fragment if (bundle.get(dtn::data::PrimaryBlock::FRAGMENT)) { // ... and set the corresponding cipher suit params addFragmentRange(pcb._ciphersuite_params, bundle.fragmentoffset, stream.size()); } // get the IV aes_stream.getIV(iv); // get the tag aes_stream.getTag(tag); } // encrypt payload - END // set the source and destination address of the new block if (source != bundle.source.getNode()) pcb.setSecuritySource( source ); if (long_key.reference != bundle.destination.getNode()) pcb.setSecurityDestination( long_key.reference ); // set replicate in every fragment to true pcb.set(REPLICATE_IN_EVERY_FRAGMENT, true); // store encypted key, tag, iv and salt addSalt(pcb._ciphersuite_params, salt); // get the RSA key RSA *rsa_key = long_key.getRSA(); // encrypt the random key and add it to the ciphersuite params addKey(pcb._ciphersuite_params, ephemeral_key, ibrcommon::AES128Stream::key_size_in_bytes, rsa_key); // free the RSA key long_key.free(rsa_key); pcb._ciphersuite_params.set(SecurityBlock::initialization_vector, iv, ibrcommon::AES128Stream::iv_len); pcb._ciphersuite_flags |= SecurityBlock::CONTAINS_CIPHERSUITE_PARAMS; pcb._security_result.set(SecurityBlock::PCB_integrity_check_value, tag, ibrcommon::AES128Stream::tag_len); pcb._ciphersuite_flags |= SecurityBlock::CONTAINS_SECURITY_RESULT; }
void PayloadConfidentialBlock::decrypt(dtn::data::Bundle& bundle, const dtn::security::SecurityKey &long_key) { // list of block to delete if the process is successful std::list<const dtn::data::Block*> erasure_list; // load the RSA key RSA *rsa_key = long_key.getRSA(); try { // array for the current symmetric AES key unsigned char key[ibrcommon::AES128Stream::key_size_in_bytes]; // correlator of the first PCB dtn::data::Number correlator = 0; bool decrypt_related = false; // iterate through all blocks for (dtn::data::Bundle::iterator it = bundle.begin(); it != bundle.end(); ++it) { try { dynamic_cast<const PayloadIntegrityBlock&>(**it); // add this block to the erasure list for later deletion erasure_list.push_back(&**it); } catch (const std::bad_cast&) { }; try { const PayloadConfidentialBlock &pcb = dynamic_cast<const PayloadConfidentialBlock&>(**it); // get salt and key uint32_t salt = getSalt(pcb._ciphersuite_params); // decrypt related blocks if (decrypt_related) { // try to decrypt the block try { decryptBlock(bundle, it, salt, key); // success! add this block to the erasue list erasure_list.push_back(&**it); } catch (const ibrcommon::Exception&) { IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL; decryptBlock(bundle, it, salt, key); // abort the decryption and discard the bundle? throw ibrcommon::Exception("decrypt of correlated block reversed, tag verfication failed"); } } // if security destination does match the key, then try to decrypt the payload else if (pcb.isSecurityDestination(bundle, long_key.reference) && (pcb._ciphersuite_id == SecurityBlock::PCB_RSA_AES128_PAYLOAD_PIB_PCB)) { // try to decrypt the symmetric AES key if (!getKey(pcb._ciphersuite_params, key, ibrcommon::AES128Stream::key_size_in_bytes, rsa_key)) { IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "could not get symmetric key decrypted" << IBRCOMMON_LOGGER_ENDL; throw ibrcommon::Exception("decrypt failed - could not get symmetric key decrypted"); } // try to decrypt the payload if (!decryptPayload(bundle, key, salt)) { // reverse decryption IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL; decryptPayload(bundle, key, salt); throw ibrcommon::Exception("decrypt reversed - tag verfication failed"); } // success! add this block to the erasue list erasure_list.push_back(&**it); // check if first PCB has a correlator if (pcb._ciphersuite_flags & CONTAINS_CORRELATOR) { // ... and decrypt all correlated block with the same key decrypt_related = true; // store the correlator correlator = pcb._correlator; } else { // no correlated blocks should exists // stop here with decryption break; } } else { // exit here, because we can not decrypt the first PCB. throw ibrcommon::Exception("unable to decrypt the first PCB"); } } catch (const std::bad_cast&) { }; } // delete all block in the erasure list for (std::list<const dtn::data::Block* >::const_iterator it = erasure_list.begin(); it != erasure_list.end(); ++it) { bundle.remove(**it); } } catch (const std::exception&) { long_key.free(rsa_key); throw; } long_key.free(rsa_key); }