LCOV - code coverage report
Current view: top level - DCPS/security - CryptoBuiltInImpl.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 389 1217 32.0 %
Date: 2023-04-30 01:32:43 Functions: 39 83 47.0 %

          Line data    Source code
       1             : /*
       2             :  * Distributed under the OpenDDS License.
       3             :  * See: http://www.opendds.org/license.html
       4             :  */
       5             : 
       6             : #include "CryptoBuiltInImpl.h"
       7             : 
       8             : #include "CryptoBuiltInTypeSupportImpl.h"
       9             : #include "CommonUtilities.h"
      10             : 
      11             : #include "SSL/Utils.h"
      12             : 
      13             : #include "dds/DdsDcpsInfrastructureC.h"
      14             : #include "dds/DdsSecurityParamsC.h"
      15             : 
      16             : #include "dds/DCPS/debug.h"
      17             : #include "dds/DCPS/GuidUtils.h"
      18             : #include "dds/DCPS/Message_Block_Ptr.h"
      19             : #include "dds/DCPS/Serializer.h"
      20             : #include "dds/DCPS/Util.h"
      21             : 
      22             : #include "dds/DCPS/RTPS/MessageUtils.h"
      23             : #include "dds/DCPS/RTPS/MessageTypes.h"
      24             : #include "dds/DCPS/RTPS/MessageParser.h"
      25             : #include "dds/DCPS/RTPS/RtpsCoreTypeSupportImpl.h"
      26             : 
      27             : #include <openssl/err.h>
      28             : #include <openssl/evp.h>
      29             : #include <openssl/rand.h>
      30             : 
      31             : #include "OpenSSL_init.h"
      32             : #include "OpenSSL_legacy.h" // Must come after all other OpenSSL includes
      33             : 
      34             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      35             : 
      36             : using namespace DDS::Security;
      37             : using namespace OpenDDS::Security::CommonUtilities;
      38             : using OpenDDS::DCPS::Serializer;
      39             : using OpenDDS::DCPS::Encoding;
      40             : using OpenDDS::DCPS::ENDIAN_BIG;
      41             : using OpenDDS::DCPS::align;
      42             : using OpenDDS::DCPS::serialized_size;
      43             : using OpenDDS::DCPS::Message_Block_Ptr;
      44             : using OpenDDS::DCPS::security_debug;
      45             : 
      46             : const Encoding common_encoding(Encoding::KIND_XCDR1, ENDIAN_BIG);
      47             : 
      48             : namespace OpenDDS {
      49             : namespace Security {
      50             : 
      51          37 : CryptoBuiltInImpl::CryptoBuiltInImpl()
      52          37 :   : mutex_()
      53          37 :   , next_handle_(1)
      54             : {
      55          37 :   openssl_init();
      56          37 : }
      57             : 
      58          40 : CryptoBuiltInImpl::~CryptoBuiltInImpl()
      59             : {
      60          37 :   if (DCPS::security_debug.bookkeeping) {
      61           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
      62             :                ACE_TEXT("CryptoBuiltInImpl::~CryptoBuiltInImpl keys_ %B encrypt_options_ %B participant_to_entity_ %B sessions_ %B derived_key_handles_ %B\n"),
      63             :                keys_.size(),
      64             :                encrypt_options_.size(),
      65             :                participant_to_entity_.size(),
      66             :                sessions_.size(),
      67             :                derived_key_handles_.size()));
      68             :   }
      69             : 
      70          37 :   openssl_cleanup();
      71          40 : }
      72             : 
      73           0 : bool CryptoBuiltInImpl::_is_a(const char* id)
      74             : {
      75           0 :   return CryptoKeyFactory::_is_a(id)
      76           0 :     || CryptoKeyExchange::_is_a(id)
      77           0 :     || CryptoTransform::_is_a(id);
      78             : }
      79             : 
      80           0 : const char* CryptoBuiltInImpl::_interface_repository_id() const
      81             : {
      82           0 :   return "";
      83             : }
      84             : 
      85           0 : bool CryptoBuiltInImpl::marshal(TAO_OutputCDR&)
      86             : {
      87           0 :   return false;
      88             : }
      89             : 
      90          39 : NativeCryptoHandle CryptoBuiltInImpl::generate_handle()
      91             : {
      92          39 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
      93          78 :   return generate_handle_i();
      94          39 : }
      95             : 
      96          42 : NativeCryptoHandle CryptoBuiltInImpl::generate_handle_i()
      97             : {
      98          42 :   return CommonUtilities::increment_handle(next_handle_);
      99             : }
     100             : 
     101             : 
     102             : // Key Factory
     103             : 
     104             : namespace {
     105             :   const unsigned int KEY_LEN_BYTES = 32;
     106             :   const unsigned int BLOCK_LEN_BYTES = 16;
     107             :   const unsigned int MAX_BLOCKS_PER_SESSION = 1024;
     108             : 
     109          19 :   KeyMaterial_AES_GCM_GMAC make_key(unsigned int key_id, bool encrypt)
     110             :   {
     111          19 :     KeyMaterial_AES_GCM_GMAC k;
     112             : 
     113          76 :     for (unsigned int i = 0; i < TransformKindIndex; ++i) {
     114          57 :       k.transformation_kind[i] = 0;
     115             :     }
     116          19 :     k.transformation_kind[TransformKindIndex] =
     117          19 :       encrypt ? CRYPTO_TRANSFORMATION_KIND_AES256_GCM
     118             :       : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC;
     119             : 
     120          19 :     k.master_salt.length(KEY_LEN_BYTES);
     121          19 :     RAND_bytes(k.master_salt.get_buffer(), KEY_LEN_BYTES);
     122             : 
     123          95 :     for (unsigned int i = 0; i < sizeof k.sender_key_id; ++i) {
     124          76 :       k.sender_key_id[i] = key_id >> (8 * i);
     125             :     }
     126             : 
     127          19 :     k.master_sender_key.length(KEY_LEN_BYTES);
     128          19 :     RAND_bytes(k.master_sender_key.get_buffer(), KEY_LEN_BYTES);
     129             : 
     130          95 :     for (unsigned int i = 0; i < sizeof k.receiver_specific_key_id; ++i) {
     131          76 :       k.receiver_specific_key_id[i] = 0;
     132             :     }
     133             : 
     134          19 :     k.master_receiver_specific_key.length(0);
     135          19 :     return k;
     136           0 :   }
     137             : 
     138             :   const unsigned submessage_key_index = 0;
     139             : }
     140             : 
     141          21 : ParticipantCryptoHandle CryptoBuiltInImpl::register_local_participant(
     142             :   IdentityHandle participant_identity,
     143             :   PermissionsHandle participant_permissions,
     144             :   const DDS::PropertySeq&,
     145             :   const ParticipantSecurityAttributes& participant_security_attributes,
     146             :   SecurityException& ex)
     147             : {
     148          21 :   if (DDS::HANDLE_NIL == participant_identity) {
     149           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant ID");
     150           1 :     return DDS::HANDLE_NIL;
     151             :   }
     152          20 :   if (DDS::HANDLE_NIL == participant_permissions) {
     153           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid local permissions");
     154           1 :     return DDS::HANDLE_NIL;
     155             :   }
     156             : 
     157          19 :   if (!participant_security_attributes.is_rtps_protected) {
     158           2 :     return DDS::HANDLE_NIL;
     159             :   }
     160             : 
     161          17 :   const NativeCryptoHandle h = generate_handle();
     162             :   const KeyMaterial key = make_key(h,
     163          17 :     participant_security_attributes.plugin_participant_attributes & PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED);
     164          17 :   KeySeq keys;
     165          17 :   DCPS::push_back(keys, key);
     166             : 
     167          17 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     168          17 :   keys_[h] = keys;
     169          17 :   if (DCPS::security_debug.bookkeeping) {
     170           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     171             :                ACE_TEXT("CryptoBuiltInImpl::register_local_participant keys_ (total %B)\n"),
     172             :                keys_.size()));
     173             :   }
     174          17 :   return h;
     175          17 : }
     176             : 
     177          13 : ParticipantCryptoHandle CryptoBuiltInImpl::register_matched_remote_participant(
     178             :   ParticipantCryptoHandle,
     179             :   IdentityHandle remote_participant_identity,
     180             :   PermissionsHandle remote_participant_permissions,
     181             :   SharedSecretHandle* shared_secret,
     182             :   SecurityException& ex)
     183             : {
     184          13 :   if (DDS::HANDLE_NIL == remote_participant_identity) {
     185           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant ID");
     186           1 :     return DDS::HANDLE_NIL;
     187             :   }
     188          12 :   if (DDS::HANDLE_NIL == remote_participant_permissions) {
     189           0 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant permissions");
     190           0 :     return DDS::HANDLE_NIL;
     191             :   }
     192          12 :   if (!shared_secret) {
     193           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret data");
     194           1 :     return DDS::HANDLE_NIL;
     195             :   }
     196             : 
     197          11 :   return generate_handle();
     198             : }
     199             : 
     200             : namespace {
     201             : 
     202           0 :   bool operator==(const TAO::String_Manager& lhs, const char* rhs)
     203             :   {
     204           0 :     return 0 == std::strcmp(lhs, rhs);
     205             :   }
     206             : 
     207           2 :   bool operator==(const char* lhs, const TAO::String_Manager& rhs)
     208             :   {
     209           2 :     return 0 == std::strcmp(lhs, rhs);
     210             :   }
     211             : 
     212          11 :   bool is_builtin_volatile(const DDS::PropertySeq& props)
     213             :   {
     214          11 :     for (unsigned int i = 0; i < props.length(); ++i) {
     215           0 :       if (props[i].name == "dds.sec.builtin_endpoint_name") {
     216           0 :         return props[i].value == "BuiltinParticipantVolatileMessageSecureWriter"
     217           0 :           || props[i].value == "BuiltinParticipantVolatileMessageSecureReader";
     218             :       }
     219             :     }
     220          11 :     return false;
     221             :   }
     222             : 
     223             :   const unsigned char VOLATILE_PLACEHOLDER_KIND[] = {DCPS::VENDORID_OCI[0], DCPS::VENDORID_OCI[1], 0, 1};
     224             : 
     225           1 :   bool is_volatile_placeholder(const KeyMaterial_AES_GCM_GMAC& keymat)
     226             :   {
     227           1 :     return 0 == std::memcmp(VOLATILE_PLACEHOLDER_KIND, keymat.transformation_kind, sizeof VOLATILE_PLACEHOLDER_KIND);
     228             :   }
     229             : 
     230           0 :   KeyMaterial_AES_GCM_GMAC make_volatile_placeholder()
     231             :   {
     232             :     // not an actual key, just used to identify the local datawriter/reader
     233             :     // crypto handle for a Built-In Participant Volatile Msg endpoint
     234           0 :     KeyMaterial_AES_GCM_GMAC k;
     235           0 :     std::memcpy(k.transformation_kind, VOLATILE_PLACEHOLDER_KIND, sizeof VOLATILE_PLACEHOLDER_KIND);
     236           0 :     std::memset(k.sender_key_id, 0, sizeof k.sender_key_id);
     237           0 :     std::memset(k.receiver_specific_key_id, 0, sizeof k.receiver_specific_key_id);
     238           0 :     return k;
     239             :   }
     240             : 
     241             :   struct PrivateKey {
     242             :     EVP_PKEY* pkey_;
     243           0 :     explicit PrivateKey(const KeyOctetSeq& key)
     244           0 :       : pkey_(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, 0, key.get_buffer(), key.length()))
     245           0 :     {}
     246           0 :     explicit PrivateKey(const DDS::OctetSeq& key)
     247           0 :       : pkey_(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, 0, key.get_buffer(), key.length()))
     248           0 :     {}
     249           0 :     operator EVP_PKEY*() { return pkey_; }
     250           0 :     ~PrivateKey() { EVP_PKEY_free(pkey_); }
     251             :   };
     252             : 
     253             :   struct DigestContext {
     254             :     EVP_MD_CTX* ctx_;
     255           0 :     DigestContext() : ctx_(EVP_MD_CTX_new()) {}
     256           0 :     operator EVP_MD_CTX*() { return ctx_; }
     257           0 :     ~DigestContext() { EVP_MD_CTX_free(ctx_); }
     258             :   };
     259             : 
     260           0 :   void hkdf(KeyOctetSeq& result, const DDS::OctetSeq_var& prefix,
     261             :             const char (&cookie)[17], const DDS::OctetSeq_var& suffix,
     262             :             const DDS::OctetSeq_var& data)
     263             :   {
     264           0 :     char* const cookie_buffer = const_cast<char*>(cookie); // OctetSeq has no const
     265           0 :     DDS::OctetSeq cookieSeq(16, 16, reinterpret_cast<CORBA::Octet*>(cookie_buffer));
     266           0 :     std::vector<const DDS::OctetSeq*> input(3);
     267           0 :     input[0] = prefix.ptr();
     268           0 :     input[1] = &cookieSeq;
     269           0 :     input[2] = suffix.ptr();
     270           0 :     DDS::OctetSeq key;
     271           0 :     if (SSL::hash(input, key) != 0) {
     272           0 :       return;
     273             :     }
     274             : 
     275           0 :     PrivateKey pkey(key);
     276           0 :     DigestContext ctx;
     277           0 :     const EVP_MD* const md = EVP_get_digestbyname("SHA256");
     278           0 :     if (EVP_DigestInit_ex(ctx, md, 0) != 1) {
     279           0 :       return;
     280             :     }
     281             : 
     282           0 :     if (EVP_DigestSignInit(ctx, 0, md, 0, pkey) != 1) {
     283           0 :       return;
     284             :     }
     285             : 
     286           0 :     if (EVP_DigestSignUpdate(ctx, data->get_buffer(), data->length()) != 1) {
     287           0 :       return;
     288             :     }
     289             : 
     290           0 :     size_t req = 0;
     291           0 :     if (EVP_DigestSignFinal(ctx, 0, &req) != 1) {
     292           0 :       return;
     293             :     }
     294             : 
     295           0 :     result.length(static_cast<unsigned int>(req));
     296           0 :     if (EVP_DigestSignFinal(ctx, result.get_buffer(), &req) != 1) {
     297           0 :       result.length(0);
     298             :     }
     299           0 :   }
     300             : 
     301             :   KeyMaterial_AES_GCM_GMAC
     302           0 :   make_volatile_key(const DDS::OctetSeq_var& challenge1,
     303             :                     const DDS::OctetSeq_var& challenge2,
     304             :                     const DDS::OctetSeq_var& sharedSec)
     305             :   {
     306             :     static const char KxSaltCookie[] = "keyexchange salt";
     307             :     static const char KxKeyCookie[] = "key exchange key";
     308           0 :     KeyMaterial_AES_GCM_GMAC k = {
     309             :       {0, 0, 0, CRYPTO_TRANSFORMATION_KIND_AES256_GCM},
     310             :       KeyOctetSeq(), {0, 0, 0, 0}, KeyOctetSeq(), {0, 0, 0, 0}, KeyOctetSeq()
     311           0 :     };
     312           0 :     hkdf(k.master_salt, challenge1, KxSaltCookie, challenge2, sharedSec);
     313           0 :     hkdf(k.master_sender_key, challenge2, KxKeyCookie, challenge1, sharedSec);
     314           0 :     return k;
     315           0 :   }
     316             : }
     317             : 
     318           7 : DatawriterCryptoHandle CryptoBuiltInImpl::register_local_datawriter(
     319             :   ParticipantCryptoHandle participant_crypto,
     320             :   const DDS::PropertySeq& properties,
     321             :   const EndpointSecurityAttributes& security_attributes,
     322             :   SecurityException&)
     323             : {
     324           7 :   const NativeCryptoHandle h = generate_handle();
     325           7 :   const PluginEndpointSecurityAttributesMask plugin_attribs =
     326             :     security_attributes.plugin_endpoint_attributes;
     327           7 :   KeySeq keys;
     328             : 
     329           7 :   if (is_builtin_volatile(properties)) {
     330           0 :     DCPS::push_back(keys, make_volatile_placeholder());
     331             : 
     332             :   } else {
     333             :     // See Table 70 "register_local_datawriter" for the use of the key sequence
     334             :     // (requirements for which key appears first, etc.)
     335           7 :     bool used_h = false;
     336           7 :     if (security_attributes.is_submessage_protected) {
     337           1 :       const KeyMaterial key = make_key(h, plugin_attribs & FLAG_IS_SUBMESSAGE_ENCRYPTED);
     338           1 :       DCPS::push_back(keys, key);
     339           1 :       used_h = true;
     340           1 :       if (security_debug.bookkeeping && !security_debug.showkeys) {
     341           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} CryptoBuiltInImpl::register_local_datawriter ")
     342             :           ACE_TEXT("created submessage key with id %C for LDWCH %d\n"),
     343             :           ctki_to_dds_string(key.sender_key_id).c_str(), h));
     344             :       }
     345           1 :       if (security_debug.showkeys) {
     346           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} CryptoBuiltInImpl::register_local_datawriter ")
     347             :           ACE_TEXT("created submessage key for LDWCH %d:\n%C"), h,
     348             :           to_dds_string(key).c_str()));
     349             :       }
     350           1 :     }
     351           7 :     if (security_attributes.is_payload_protected) {
     352           0 :       const unsigned int key_id = used_h ? generate_handle() : h;
     353           0 :       const KeyMaterial_AES_GCM_GMAC key = make_key(key_id, plugin_attribs & FLAG_IS_PAYLOAD_ENCRYPTED);
     354           0 :       DCPS::push_back(keys, key);
     355           0 :       if (security_debug.bookkeeping && !security_debug.showkeys) {
     356           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} CryptoBuiltInImpl::register_local_datawriter ")
     357             :           ACE_TEXT("created payload key with id %C for LDWCH %d\n"),
     358             :           ctki_to_dds_string(key.sender_key_id).c_str(), h));
     359             :       }
     360           0 :       if (security_debug.showkeys) {
     361           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} CryptoBuiltInImpl::register_local_datawriter ")
     362             :           ACE_TEXT("created payload key for LDWCH %d:\n%C"), h,
     363             :           to_dds_string(key).c_str()));
     364             :       }
     365           0 :     }
     366             :   }
     367             : 
     368           7 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     369           7 :   keys_[h] = keys;
     370           7 :   if (DCPS::security_debug.bookkeeping) {
     371           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     372             :                ACE_TEXT("CryptoBuiltInImpl::register_local_datawriter keys_ (total %B)\n"),
     373             :                keys_.size()));
     374             :   }
     375           7 :   encrypt_options_[h] = security_attributes;
     376           7 :   if (DCPS::security_debug.bookkeeping) {
     377           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     378             :                ACE_TEXT("CryptoBuiltInImpl::register_local_datawriter encrypt_options_ (total %B)\n"),
     379             :                encrypt_options_.size()));
     380             :   }
     381             : 
     382           7 :   if (participant_crypto != DDS::HANDLE_NIL) {
     383           2 :     const EntityInfo e(DATAWRITER_SUBMESSAGE, h);
     384           2 :     participant_to_entity_.insert(std::make_pair(participant_crypto, e));
     385           2 :     if (DCPS::security_debug.bookkeeping) {
     386           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     387             :                  ACE_TEXT("CryptoBuiltInImpl::register_local_datawriter participant_to_entity_ (total %B)\n"),
     388             :                  participant_to_entity_.size()));
     389             :     }
     390             :   }
     391             : 
     392           7 :   return h;
     393           7 : }
     394             : 
     395           4 : DatareaderCryptoHandle CryptoBuiltInImpl::register_matched_remote_datareader(
     396             :   DatawriterCryptoHandle local_datawriter_crypto_handle,
     397             :   ParticipantCryptoHandle remote_participant_crypto,
     398             :   SharedSecretHandle* shared_secret,
     399             :   bool /*relay_only*/,
     400             :   SecurityException& ex)
     401             : {
     402           4 :   if (DDS::HANDLE_NIL == local_datawriter_crypto_handle) {
     403           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataWriter Crypto Handle");
     404           1 :     return DDS::HANDLE_NIL;
     405             :   }
     406           3 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     407           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Remote Participant Crypto Handle");
     408           1 :     return DDS::HANDLE_NIL;
     409             :   }
     410           2 :   if (!shared_secret) {
     411           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret Handle");
     412           1 :     return DDS::HANDLE_NIL;
     413             :   }
     414             : 
     415           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     416           1 :   const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto_handle);
     417           1 :   if (iter == keys_.end()) {
     418           0 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataWriter Crypto Handle");
     419           0 :     return DDS::HANDLE_NIL;
     420             :   }
     421             : 
     422           1 :   const KeySeq& dw_keys = iter->second;
     423           1 :   const bool use_derived_key = dw_keys.length() == 1 && is_volatile_placeholder(dw_keys[0]);
     424             : 
     425           1 :   const HandlePair_t input_handles = std::make_pair(remote_participant_crypto, local_datawriter_crypto_handle);
     426             :   const DerivedKeyIndex_t::iterator existing_handle_iter =
     427           1 :     use_derived_key ? derived_key_handles_.find(input_handles) : derived_key_handles_.end();
     428             :   const DatareaderCryptoHandle h =
     429           1 :     (existing_handle_iter == derived_key_handles_.end())
     430           1 :     ? generate_handle_i() : existing_handle_iter->second;
     431             : 
     432           1 :   if (use_derived_key) {
     433             :     // Create a key from SharedSecret and track it as if Key Exchange happened
     434           0 :     KeySeq dr_keys(1);
     435           0 :     dr_keys.length(1);
     436           0 :     dr_keys[0] = make_volatile_key(shared_secret->challenge1(),
     437           0 :                                    shared_secret->challenge2(),
     438           0 :                                    shared_secret->sharedSecret());
     439           0 :     if (!dr_keys[0].master_salt.length()
     440           0 :         || !dr_keys[0].master_sender_key.length()) {
     441           0 :       CommonUtilities::set_security_error(ex, -1, 0, "Couldn't create key for "
     442             :                                           "volatile remote reader");
     443           0 :       return DDS::HANDLE_NIL;
     444             :     }
     445           0 :     if (security_debug.bookkeeping && !security_debug.showkeys) {
     446           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     447             :         ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader ")
     448             :         ACE_TEXT("created volatile key for RDRCH %d\n"), h));
     449             :     }
     450           0 :     if (security_debug.showkeys) {
     451           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} ")
     452             :         ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader ")
     453             :         ACE_TEXT("created volatile key for RDRCH %d:\n%C"), h,
     454             :         to_dds_string(dr_keys[0]).c_str()));
     455             :     }
     456           0 :     keys_[h] = dr_keys;
     457           0 :     if (DCPS::security_debug.bookkeeping) {
     458           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     459             :                  ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader keys_ (total %B)\n"),
     460             :                  keys_.size()));
     461             :     }
     462           0 :     if (existing_handle_iter != derived_key_handles_.end()) {
     463           0 :       sessions_.erase(std::make_pair(h, submessage_key_index));
     464           0 :       if (DCPS::security_debug.bookkeeping) {
     465           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     466             :                    ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader sessions_ (total %B)\n"),
     467             :                    sessions_.size()));
     468             :       }
     469             :     } else {
     470           0 :       derived_key_handles_[input_handles] = h;
     471           0 :       if (DCPS::security_debug.bookkeeping) {
     472           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     473             :                    ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader derived_key_handles_ (total %B)\n"),
     474             :                    derived_key_handles_.size()));
     475             :       }
     476             :     }
     477           0 :   }
     478             : 
     479           1 :   const EntityInfo e(DATAREADER_SUBMESSAGE, h);
     480           1 :   participant_to_entity_.insert(std::make_pair(remote_participant_crypto, e));
     481           1 :   if (DCPS::security_debug.bookkeeping) {
     482           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     483             :                ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader participant_to_entity_ (total %B)\n"),
     484             :                participant_to_entity_.size()));
     485             :   }
     486           1 :   encrypt_options_[h] = encrypt_options_[local_datawriter_crypto_handle];
     487           1 :   if (DCPS::security_debug.bookkeeping) {
     488           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     489             :                ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datareader encrypt_options_ (total %B)\n"),
     490             :                encrypt_options_.size()));
     491             :   }
     492           1 :   return h;
     493           1 : }
     494             : 
     495           4 : DatareaderCryptoHandle CryptoBuiltInImpl::register_local_datareader(
     496             :   ParticipantCryptoHandle participant_crypto,
     497             :   const DDS::PropertySeq& properties,
     498             :   const EndpointSecurityAttributes& security_attributes,
     499             :   SecurityException&)
     500             : {
     501           4 :   const NativeCryptoHandle h = generate_handle();
     502           4 :   const PluginEndpointSecurityAttributesMask plugin_attribs = security_attributes.plugin_endpoint_attributes;
     503           4 :   KeySeq keys;
     504             : 
     505           4 :   if (is_builtin_volatile(properties)) {
     506           0 :     DCPS::push_back(keys, make_volatile_placeholder());
     507             : 
     508           4 :   } else if (security_attributes.is_submessage_protected) {
     509           1 :     const KeyMaterial key = make_key(h, plugin_attribs & FLAG_IS_SUBMESSAGE_ENCRYPTED);
     510           1 :     if (security_debug.bookkeeping && !security_debug.showkeys) {
     511           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} CryptoBuiltInImpl::register_local_datareader ")
     512             :         ACE_TEXT("created submessage key with id %C for LDRCH %d\n"),
     513             :         ctki_to_dds_string(key.sender_key_id).c_str(), h));
     514             :     }
     515           1 :     if (security_debug.showkeys) {
     516           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} CryptoBuiltInImpl::register_local_datareader ")
     517             :         ACE_TEXT("created submessage key for LDRCH %d:\n%C"), h,
     518             :         to_dds_string(key).c_str()));
     519             :     }
     520           1 :     DCPS::push_back(keys, key);
     521           1 :   }
     522             : 
     523           4 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     524           4 :   keys_[h] = keys;
     525           4 :   if (DCPS::security_debug.bookkeeping) {
     526           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     527             :                ACE_TEXT("CryptoBuiltInImpl::register_local_datareader keys_ (total %B)\n"),
     528             :                keys_.size()));
     529             :   }
     530           4 :   encrypt_options_[h] = security_attributes;
     531           4 :   if (DCPS::security_debug.bookkeeping) {
     532           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     533             :                ACE_TEXT("CryptoBuiltInImpl::register_local_datareader encrypt_options_ (total %B)\n"),
     534             :                encrypt_options_.size()));
     535             :   }
     536             : 
     537           4 :   if (participant_crypto != DDS::HANDLE_NIL) {
     538           2 :     const EntityInfo e(DATAREADER_SUBMESSAGE, h);
     539           2 :     participant_to_entity_.insert(std::make_pair(participant_crypto, e));
     540           2 :     if (DCPS::security_debug.bookkeeping) {
     541           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     542             :                  ACE_TEXT("CryptoBuiltInImpl::register_local_datareader participant_to_entity_ (total %B)\n"),
     543             :                  participant_to_entity_.size()));
     544             :     }
     545             :   }
     546             : 
     547           4 :   return h;
     548           4 : }
     549             : 
     550           5 : DatawriterCryptoHandle CryptoBuiltInImpl::register_matched_remote_datawriter(
     551             :   DatareaderCryptoHandle local_datareader_crypto_handle,
     552             :   ParticipantCryptoHandle remote_participant_crypto,
     553             :   SharedSecretHandle* shared_secret,
     554             :   SecurityException& ex)
     555             : {
     556           5 :   if (DDS::HANDLE_NIL == local_datareader_crypto_handle) {
     557           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataReader Crypto Handle");
     558           1 :     return DDS::HANDLE_NIL;
     559             :   }
     560           4 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     561           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Remote Participant Crypto Handle");
     562           1 :     return DDS::HANDLE_NIL;
     563             :   }
     564           3 :   if (!shared_secret) {
     565           1 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret Handle");
     566           1 :     return DDS::HANDLE_NIL;
     567             :   }
     568             : 
     569           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     570           2 :   const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto_handle);
     571           2 :   if (iter == keys_.end()) {
     572           0 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataReader Crypto Handle");
     573           0 :     return DDS::HANDLE_NIL;
     574             :   }
     575             : 
     576           2 :   const KeySeq& dr_keys = iter->second;
     577           2 :   const bool use_derived_key = dr_keys.length() == 1 && is_volatile_placeholder(dr_keys[0]);
     578             : 
     579           2 :   const HandlePair_t input_handles = std::make_pair(remote_participant_crypto, local_datareader_crypto_handle);
     580             :   const DerivedKeyIndex_t::iterator existing_handle_iter =
     581           2 :     use_derived_key ? derived_key_handles_.find(input_handles) : derived_key_handles_.end();
     582             :   const DatareaderCryptoHandle h =
     583           2 :     (existing_handle_iter == derived_key_handles_.end())
     584           2 :     ? generate_handle_i() : existing_handle_iter->second;
     585             : 
     586           2 :   if (use_derived_key) {
     587             :     // Create a key from SharedSecret and track it as if Key Exchange happened
     588           0 :     KeySeq dw_keys(1);
     589           0 :     dw_keys.length(1);
     590           0 :     dw_keys[0] = make_volatile_key(shared_secret->challenge1(),
     591           0 :                                    shared_secret->challenge2(),
     592           0 :                                    shared_secret->sharedSecret());
     593           0 :     if (!dw_keys[0].master_salt.length()
     594           0 :         || !dw_keys[0].master_sender_key.length()) {
     595           0 :       CommonUtilities::set_security_error(ex, -1, 0, "Couldn't create key for "
     596             :                                           "volatile remote writer");
     597           0 :       return DDS::HANDLE_NIL;
     598             :     }
     599           0 :     if (security_debug.bookkeeping && !security_debug.showkeys) {
     600           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     601             :         ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter ")
     602             :         ACE_TEXT("created volatile key for RDWCH %d\n"), h));
     603             :     }
     604           0 :     if (security_debug.showkeys) {
     605           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} ")
     606             :         ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter ")
     607             :         ACE_TEXT("created volatile key for RDWCH %d:\n%C"), h,
     608             :         to_dds_string(dw_keys[0]).c_str()));
     609             :     }
     610           0 :     keys_[h] = dw_keys;
     611           0 :     if (DCPS::security_debug.bookkeeping) {
     612           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     613             :                  ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter keys_ (total %B)\n"),
     614             :                  keys_.size()));
     615             :     }
     616           0 :     if (existing_handle_iter != derived_key_handles_.end()) {
     617           0 :       sessions_.erase(std::make_pair(h, submessage_key_index));
     618           0 :       if (DCPS::security_debug.bookkeeping) {
     619           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     620             :                    ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter sessions_ (total %B)\n"),
     621             :                    sessions_.size()));
     622             :       }
     623             :     } else {
     624           0 :       derived_key_handles_[input_handles] = h;
     625           0 :       if (DCPS::security_debug.bookkeeping) {
     626           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     627             :                    ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter derived_key_handles_ (total %B)\n"),
     628             :                    derived_key_handles_.size()));
     629             :       }
     630             :     }
     631           0 :   }
     632             : 
     633           2 :   const EntityInfo e(DATAWRITER_SUBMESSAGE, h);
     634           2 :   participant_to_entity_.insert(std::make_pair(remote_participant_crypto, e));
     635           2 :   if (DCPS::security_debug.bookkeeping) {
     636           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     637             :                ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter participant_to_entity_ (total %B)\n"),
     638             :                participant_to_entity_.size()));
     639             :   }
     640           2 :   encrypt_options_[h] = encrypt_options_[local_datareader_crypto_handle];
     641           2 :   if (DCPS::security_debug.bookkeeping) {
     642           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     643             :                ACE_TEXT("CryptoBuiltInImpl::register_matched_remote_datawriter encrypt_options_ (total %B)\n"),
     644             :                encrypt_options_.size()));
     645             :   }
     646           2 :   return h;
     647           2 : }
     648             : 
     649           1 : bool CryptoBuiltInImpl::unregister_participant(ParticipantCryptoHandle handle, SecurityException& ex)
     650             : {
     651           1 :   if (DDS::HANDLE_NIL == handle) {
     652           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
     653             :   }
     654             : 
     655           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     656           1 :   clear_common_data(handle);
     657           1 :   for (DerivedKeyIndex_t::iterator it = derived_key_handles_.lower_bound(std::make_pair(handle, 0));
     658           1 :        it != derived_key_handles_.end() && it->first.first == handle; derived_key_handles_.erase(it++)) {
     659           0 :     if (DCPS::security_debug.bookkeeping) {
     660           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     661             :                  ACE_TEXT("CryptoBuiltInImpl::unregister_participant derived_key_handles_ (total %B)\n"),
     662             :                  derived_key_handles_.size()));
     663             :     }
     664             :   }
     665           1 :   return true;
     666           1 : }
     667             : 
     668           3 : void CryptoBuiltInImpl::clear_common_data(NativeCryptoHandle handle)
     669             : {
     670           3 :   keys_.erase(handle);
     671           3 :   if (DCPS::security_debug.bookkeeping) {
     672           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     673             :                ACE_TEXT("CryptoBuiltInImpl::clear_common_data keys_ (total %B)\n"),
     674             :                keys_.size()));
     675             :   }
     676           3 :   for (SessionTable_t::iterator st_iter = sessions_.lower_bound(std::make_pair(handle, 0));
     677           3 :        st_iter != sessions_.end() && st_iter->first.first == handle;
     678           0 :        sessions_.erase(st_iter++)) {
     679           0 :     if (DCPS::security_debug.bookkeeping) {
     680           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     681             :                  ACE_TEXT("CryptoBuiltInImpl::clear_common_data sessions_ (total %B)\n"),
     682             :                  sessions_.size()));
     683             :     }
     684             :   }
     685           3 : }
     686             : 
     687           2 : void CryptoBuiltInImpl::clear_endpoint_data(NativeCryptoHandle handle)
     688             : {
     689           2 :   clear_common_data(handle);
     690           2 :   encrypt_options_.erase(handle);
     691           2 :   if (DCPS::security_debug.bookkeeping) {
     692           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     693             :                ACE_TEXT("CryptoBuiltInImpl::clear_endpoint_data encrypt_options_ (total %B)\n"),
     694             :                encrypt_options_.size()));
     695             :   }
     696             : 
     697             :   typedef std::multimap<ParticipantCryptoHandle, EntityInfo>::iterator iter_t;
     698           4 :   for (iter_t it = participant_to_entity_.begin(); it != participant_to_entity_.end();) {
     699           2 :     if (it->second.handle_ == handle) {
     700           2 :       participant_to_entity_.erase(it++);
     701           2 :       if (DCPS::security_debug.bookkeeping) {
     702           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     703             :                    ACE_TEXT("CryptoBuiltInImpl::clear_endpoint_data participant_to_entity_ (total %B)\n"),
     704             :                    participant_to_entity_.size()));
     705             :       }
     706             :     } else {
     707           0 :       ++it;
     708             :     }
     709             :   }
     710           2 : }
     711             : 
     712           1 : bool CryptoBuiltInImpl::unregister_datawriter(DatawriterCryptoHandle handle, SecurityException& ex)
     713             : {
     714           1 :   if (DDS::HANDLE_NIL == handle) {
     715           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
     716             :   }
     717             : 
     718           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     719           1 :   clear_endpoint_data(handle);
     720           1 :   return true;
     721           1 : }
     722             : 
     723           1 : bool CryptoBuiltInImpl::unregister_datareader(DatareaderCryptoHandle handle, SecurityException& ex)
     724             : {
     725           1 :   if (DDS::HANDLE_NIL == handle) {
     726           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
     727             :   }
     728             : 
     729           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     730           1 :   clear_endpoint_data(handle);
     731           1 :   return true;
     732           1 : }
     733             : 
     734             : 
     735             : // Key Exchange
     736             : 
     737             : namespace {
     738             :   const char Crypto_Token_Class_Id[] = "DDS:Crypto:AES_GCM_GMAC";
     739             :   const char Token_KeyMat_Name[] = "dds.cryp.keymat";
     740             : 
     741           3 :   const char* to_mb(const unsigned char* buffer)
     742             :   {
     743           3 :     return reinterpret_cast<const char*>(buffer);
     744             :   }
     745             : 
     746           1 :   ParticipantCryptoTokenSeq keys_to_tokens(const KeyMaterial_AES_GCM_GMAC_Seq& keys)
     747             :   {
     748           1 :     ParticipantCryptoTokenSeq tokens;
     749           2 :     for (unsigned int i = 0; i < keys.length(); ++i) {
     750           1 :       CryptoToken t;
     751           1 :       t.class_id = Crypto_Token_Class_Id;
     752           1 :       t.binary_properties.length(1);
     753           1 :       DDS::BinaryProperty_t& p = t.binary_properties[0];
     754           1 :       p.name = Token_KeyMat_Name;
     755           1 :       p.propagate = true;
     756           1 :       const size_t size = serialized_size(common_encoding, keys[i]);
     757           1 :       p.value.length(static_cast<unsigned int>(size));
     758           1 :       ACE_Message_Block mb(to_mb(p.value.get_buffer()), size);
     759           1 :       Serializer ser(&mb, common_encoding);
     760           1 :       if (ser << keys[i]) {
     761           1 :         DCPS::push_back(tokens, t);
     762             :       } else {
     763           0 :         ACE_ERROR((LM_ERROR,
     764             :           "(%P|%t) ERROR: keys_to_tokens: Failed to serialize\n"));
     765             :       }
     766           1 :     }
     767           1 :     return tokens;
     768           0 :   }
     769             : 
     770           4 :   KeyMaterial_AES_GCM_GMAC_Seq tokens_to_keys(const ParticipantCryptoTokenSeq& tokens)
     771             :   {
     772           4 :     KeyMaterial_AES_GCM_GMAC_Seq keys;
     773           5 :     for (unsigned int i = 0; i < tokens.length(); ++i) {
     774           1 :       const CryptoToken& t = tokens[i];
     775           1 :       if (Crypto_Token_Class_Id == t.class_id) {
     776           1 :         for (unsigned int j = 0; j < t.binary_properties.length(); ++j) {
     777           1 :           const DDS::BinaryProperty_t& p = t.binary_properties[j];
     778           1 :           if (Token_KeyMat_Name == p.name) {
     779           1 :             ACE_Message_Block mb(to_mb(p.value.get_buffer()), p.value.length());
     780           1 :             mb.wr_ptr(p.value.length());
     781           1 :             Serializer ser(&mb, common_encoding);
     782           1 :             KeyMaterial_AES_GCM_GMAC key;
     783           1 :             if (ser >> key) {
     784           1 :               DCPS::push_back(keys, key);
     785             :             } else {
     786           0 :               ACE_ERROR((LM_ERROR,
     787             :                 "(%P|%t) ERROR: tokens_to_keys: Failed to deserialize\n"));
     788             :             }
     789           1 :             break;
     790           1 :           }
     791             :         }
     792             :       }
     793             :     }
     794           4 :     return keys;
     795           0 :   }
     796             : }
     797             : 
     798           2 : bool CryptoBuiltInImpl::create_local_participant_crypto_tokens(
     799             :   ParticipantCryptoTokenSeq& local_participant_crypto_tokens,
     800             :   ParticipantCryptoHandle local_participant_crypto,
     801             :   ParticipantCryptoHandle remote_participant_crypto,
     802             :   SecurityException& ex)
     803             : {
     804           2 :   if (DDS::HANDLE_NIL == local_participant_crypto) {
     805           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant handle");
     806             :   }
     807           1 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     808           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant handle");
     809             :   }
     810             : 
     811           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     812           0 :   const KeyTable_t::const_iterator iter = keys_.find(local_participant_crypto);
     813           0 :   if (iter != keys_.end()) {
     814           0 :     local_participant_crypto_tokens = keys_to_tokens(iter->second);
     815             :   } else {
     816             :     // There may not be any keys_ for this participant (depends on config)
     817           0 :     local_participant_crypto_tokens.length(0);
     818             :   }
     819             : 
     820           0 :   return true;
     821           0 : }
     822             : 
     823           0 : bool CryptoBuiltInImpl::have_local_participant_crypto_tokens(
     824             :   DDS::Security::ParticipantCryptoHandle local_participant_crypto,
     825             :   DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
     826             : {
     827           0 :   if (DDS::HANDLE_NIL == local_participant_crypto) {
     828           0 :     return false;
     829             :   }
     830           0 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     831           0 :     return false;
     832             :   }
     833             : 
     834           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     835           0 :   const KeyTable_t::const_iterator iter = keys_.find(local_participant_crypto);
     836           0 :   if (iter == keys_.end()) {
     837           0 :     return false;
     838             :   }
     839           0 :   return iter->second.length();
     840           0 : }
     841             : 
     842           1 : bool CryptoBuiltInImpl::set_remote_participant_crypto_tokens(
     843             :   ParticipantCryptoHandle local_participant_crypto,
     844             :   ParticipantCryptoHandle remote_participant_crypto,
     845             :   const ParticipantCryptoTokenSeq& remote_participant_tokens,
     846             :   SecurityException& ex)
     847             : {
     848           1 :   if (DDS::HANDLE_NIL == local_participant_crypto) {
     849           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant handle");
     850             :   }
     851           1 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     852           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant handle");
     853             :   }
     854             : 
     855           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     856           1 :   keys_[remote_participant_crypto] = tokens_to_keys(remote_participant_tokens);
     857           1 :   if (DCPS::security_debug.bookkeeping) {
     858           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     859             :                ACE_TEXT("CryptoBuiltInImpl::set_remote_participant_crypto_tokens keys_ (total %B)\n"),
     860             :                keys_.size()));
     861             :   }
     862           1 :   return true;
     863           1 : }
     864             : 
     865           0 : bool CryptoBuiltInImpl::have_remote_participant_crypto_tokens(
     866             :   DDS::Security::ParticipantCryptoHandle local_participant_crypto,
     867             :   DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
     868             : {
     869           0 :   if (DDS::HANDLE_NIL == local_participant_crypto) {
     870           0 :     return false;
     871             :   }
     872           0 :   if (DDS::HANDLE_NIL == remote_participant_crypto) {
     873           0 :     return false;
     874             :   }
     875             : 
     876           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     877           0 :   const KeyTable_t::const_iterator iter = keys_.find(remote_participant_crypto);
     878           0 :   if (iter == keys_.end()) {
     879           0 :     return false;
     880             :   }
     881           0 :   return iter->second.length();
     882           0 : }
     883             : 
     884           4 : bool CryptoBuiltInImpl::create_local_datawriter_crypto_tokens(
     885             :   DatawriterCryptoTokenSeq& local_datawriter_crypto_tokens,
     886             :   DatawriterCryptoHandle local_datawriter_crypto,
     887             :   DatareaderCryptoHandle remote_datareader_crypto,
     888             :   SecurityException& ex)
     889             : {
     890           4 :   if (DDS::HANDLE_NIL == local_datawriter_crypto) {
     891           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local writer handle");
     892             :   }
     893           3 :   if (DDS::HANDLE_NIL == remote_datareader_crypto) {
     894           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote reader handle");
     895             :   }
     896             : 
     897           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     898           2 :   const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto);
     899           2 :   if (iter != keys_.end()) {
     900           1 :     local_datawriter_crypto_tokens = keys_to_tokens(iter->second);
     901             :   } else {
     902           1 :     local_datawriter_crypto_tokens.length(0);
     903             :   }
     904             : 
     905           2 :   return true;
     906           2 : }
     907             : 
     908           0 : bool CryptoBuiltInImpl::have_local_datawriter_crypto_tokens(
     909             :   DatawriterCryptoHandle local_datawriter_crypto,
     910             :   DatareaderCryptoHandle remote_datareader_crypto)
     911             : {
     912           0 :   if (DDS::HANDLE_NIL == local_datawriter_crypto) {
     913           0 :     return false;
     914             :   }
     915           0 :   if (DDS::HANDLE_NIL == remote_datareader_crypto) {
     916           0 :     return false;
     917             :   }
     918             : 
     919           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     920           0 :   const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto);
     921           0 :   if (iter == keys_.end()) {
     922           0 :     return false;
     923             :   }
     924           0 :   return iter->second.length();
     925           0 : }
     926             : 
     927           2 : bool CryptoBuiltInImpl::set_remote_datawriter_crypto_tokens(
     928             :   DatareaderCryptoHandle local_datareader_crypto,
     929             :   DatawriterCryptoHandle remote_datawriter_crypto,
     930             :   const DatawriterCryptoTokenSeq& remote_datawriter_tokens,
     931             :   SecurityException& ex)
     932             : {
     933           2 :   if (DDS::HANDLE_NIL == local_datareader_crypto) {
     934           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local datareader handle");
     935             :   }
     936           2 :   if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
     937           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote datawriter handle");
     938             :   }
     939             : 
     940           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     941           2 :   keys_[remote_datawriter_crypto] = tokens_to_keys(remote_datawriter_tokens);
     942           2 :   if (DCPS::security_debug.bookkeeping) {
     943           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
     944             :                ACE_TEXT("CryptoBuiltInImpl::set_remote_datawriter_crypto_tokens keys_ (total %B)\n"),
     945             :                keys_.size()));
     946             :   }
     947           2 :   return true;
     948           2 : }
     949             : 
     950           0 : bool CryptoBuiltInImpl::have_remote_datawriter_crypto_tokens(
     951             :   DatareaderCryptoHandle local_datareader_crypto,
     952             :   DatawriterCryptoHandle remote_datawriter_crypto)
     953             : {
     954           0 :   if (DDS::HANDLE_NIL == local_datareader_crypto) {
     955           0 :     return false;
     956             :   }
     957           0 :   if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
     958           0 :     return false;
     959             :   }
     960             : 
     961           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     962           0 :   const KeyTable_t::const_iterator iter = keys_.find(remote_datawriter_crypto);
     963           0 :   if (iter == keys_.end()) {
     964           0 :     return false;
     965             :   }
     966           0 :   return iter->second.length();
     967           0 : }
     968             : 
     969           3 : bool CryptoBuiltInImpl::create_local_datareader_crypto_tokens(
     970             :   DatareaderCryptoTokenSeq& local_datareader_crypto_tokens,
     971             :   DatareaderCryptoHandle local_datareader_crypto,
     972             :   DatawriterCryptoHandle remote_datawriter_crypto,
     973             :   SecurityException& ex)
     974             : {
     975           3 :   if (DDS::HANDLE_NIL == local_datareader_crypto) {
     976           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local reader handle");
     977             :   }
     978           2 :   if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
     979           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote writer handle");
     980             :   }
     981             : 
     982           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
     983           1 :   const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto);
     984           1 :   if (iter != keys_.end()) {
     985           0 :     local_datareader_crypto_tokens = keys_to_tokens(iter->second);
     986             :   } else {
     987           1 :     local_datareader_crypto_tokens.length(0);
     988             :   }
     989             : 
     990           1 :   return true;
     991           1 : }
     992             : 
     993           0 : bool CryptoBuiltInImpl::have_local_datareader_crypto_tokens(
     994             :   DatareaderCryptoHandle local_datareader_crypto,
     995             :   DatawriterCryptoHandle remote_datawriter_crypto)
     996             : {
     997           0 :   if (DDS::HANDLE_NIL == local_datareader_crypto) {
     998           0 :     return false;
     999             :   }
    1000           0 :   if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
    1001           0 :     return false;
    1002             :   }
    1003             : 
    1004           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1005           0 :   const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto);
    1006           0 :   if (iter == keys_.end()) {
    1007           0 :     return false;
    1008             :   }
    1009           0 :   return iter->second.length();
    1010           0 : }
    1011             : 
    1012           1 : bool CryptoBuiltInImpl::set_remote_datareader_crypto_tokens(
    1013             :   DatawriterCryptoHandle local_datawriter_crypto,
    1014             :   DatareaderCryptoHandle remote_datareader_crypto,
    1015             :   const DatareaderCryptoTokenSeq& remote_datareader_tokens,
    1016             :   SecurityException& ex)
    1017             : {
    1018           1 :   if (DDS::HANDLE_NIL == local_datawriter_crypto) {
    1019           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local datawriter handle");
    1020             :   }
    1021           1 :   if (DDS::HANDLE_NIL == remote_datareader_crypto) {
    1022           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote datareader handle");
    1023             :   }
    1024             : 
    1025           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1026           1 :   keys_[remote_datareader_crypto] = tokens_to_keys(remote_datareader_tokens);
    1027           1 :   if (DCPS::security_debug.bookkeeping) {
    1028           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
    1029             :                ACE_TEXT("CryptoBuiltInImpl::set_remote_datareader_crypto_tokens keys_ (total %B)\n"),
    1030             :                keys_.size()));
    1031             :   }
    1032           1 :   return true;
    1033           1 : }
    1034             : 
    1035           0 : bool CryptoBuiltInImpl::have_remote_datareader_crypto_tokens(
    1036             :   DatawriterCryptoHandle local_datawriter_crypto,
    1037             :   DatareaderCryptoHandle remote_datareader_crypto)
    1038             : {
    1039           0 :   if (DDS::HANDLE_NIL == local_datawriter_crypto) {
    1040           0 :     return false;
    1041             :   }
    1042           0 :   if (DDS::HANDLE_NIL == remote_datareader_crypto) {
    1043           0 :     return false;
    1044             :   }
    1045             : 
    1046           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1047           0 :   const KeyTable_t::const_iterator iter = keys_.find(remote_datareader_crypto);
    1048           0 :   if (iter == keys_.end()) {
    1049           0 :     return false;
    1050             :   }
    1051           0 :   return iter->second.length();
    1052           0 : }
    1053             : 
    1054           0 : bool CryptoBuiltInImpl::return_crypto_tokens(const CryptoTokenSeq&, SecurityException&)
    1055             : {
    1056           0 :   return true;
    1057             : }
    1058             : 
    1059             : 
    1060             : // Transform
    1061             : 
    1062             : namespace {
    1063           0 :   bool encrypts(const KeyMaterial_AES_GCM_GMAC& k)
    1064             :   {
    1065           0 :     const CryptoTransformKind& kind = k.transformation_kind;
    1066           0 :     return kind[0] == 0 && kind[1] == 0 && kind[2] == 0
    1067           0 :       && (kind[TransformKindIndex] == CRYPTO_TRANSFORMATION_KIND_AES128_GCM ||
    1068           0 :           kind[TransformKindIndex] == CRYPTO_TRANSFORMATION_KIND_AES256_GCM);
    1069             :   }
    1070             : 
    1071           0 :   bool authenticates(const KeyMaterial_AES_GCM_GMAC& k)
    1072             :   {
    1073           0 :     const CryptoTransformKind& kind = k.transformation_kind;
    1074           0 :     return kind[0] == 0 && kind[1] == 0 && kind[2] == 0
    1075           0 :       && (kind[TransformKindIndex] == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC ||
    1076           0 :           kind[TransformKindIndex] == CRYPTO_TRANSFORMATION_KIND_AES256_GMAC);
    1077             :   }
    1078             : 
    1079             :   struct CipherContext {
    1080             :     EVP_CIPHER_CTX* ctx_;
    1081           0 :     CipherContext() : ctx_(EVP_CIPHER_CTX_new()) {}
    1082           0 :     operator EVP_CIPHER_CTX*() { return ctx_; }
    1083           0 :     ~CipherContext() { EVP_CIPHER_CTX_free(ctx_); }
    1084             :   };
    1085             : 
    1086           0 :   bool inc32(unsigned char* a)
    1087             :   {
    1088           0 :     for (int i = 0; i < 4; ++i) {
    1089           0 :       if (a[i] != 0xff) {
    1090           0 :         ++a[i];
    1091           0 :         return false;
    1092             :       }
    1093             :     }
    1094           0 :     std::fill(a, a + 4, 0);
    1095           0 :     return true;
    1096             :   }
    1097             : 
    1098             :   const size_t CRYPTO_CONTENT_ADDED_LENGTH = 4;
    1099             :   const size_t CRYPTO_HEADER_LENGTH = 20;
    1100             : }
    1101             : 
    1102           3 : bool CryptoBuiltInImpl::encode_serialized_payload(
    1103             :   DDS::OctetSeq& encoded_buffer,
    1104             :   DDS::OctetSeq& /*extra_inline_qos*/,
    1105             :   const DDS::OctetSeq& plain_buffer,
    1106             :   DatawriterCryptoHandle sending_datawriter_crypto,
    1107             :   SecurityException& ex)
    1108             : {
    1109           3 :   if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
    1110           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid datawriter handle");
    1111             :   }
    1112             : 
    1113           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1114           2 :   const KeyTable_t::const_iterator keys_iter = keys_.find(sending_datawriter_crypto);
    1115           2 :   const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(sending_datawriter_crypto);
    1116           2 :   if (eo_iter == encrypt_options_.end()) {
    1117           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
    1118             :   }
    1119           2 :   if (keys_iter == keys_.end() || !eo_iter->second.payload_) {
    1120           2 :     encoded_buffer = plain_buffer;
    1121           2 :     return true;
    1122             :   }
    1123             : 
    1124           0 :   const KeySeq& keyseq = keys_iter->second;
    1125           0 :   if (!keyseq.length()) {
    1126           0 :     encoded_buffer = plain_buffer;
    1127           0 :     return true;
    1128             :   }
    1129             : 
    1130             :   bool ok;
    1131             :   CryptoHeader header;
    1132           0 :   CryptoFooter footer;
    1133           0 :   DDS::OctetSeq out;
    1134           0 :   const DDS::OctetSeq* pOut = &plain_buffer;
    1135             :   // see register_local_datawriter for the assignment of key indexes in the seq
    1136           0 :   const unsigned int key_idx = keyseq.length() >= 2 ? 1 : 0;
    1137           0 :   const KeyId_t sKey = std::make_pair(sending_datawriter_crypto, key_idx);
    1138             : 
    1139           0 :   if (encrypts(keyseq[key_idx])) {
    1140           0 :     ok = encrypt(keyseq[key_idx], sessions_[sKey], plain_buffer,
    1141             :                  header, footer, out, ex);
    1142           0 :     pOut = &out;
    1143             : 
    1144           0 :   } else if (authenticates(keyseq[key_idx])) {
    1145           0 :     ok = authtag(keyseq[key_idx], sessions_[sKey], plain_buffer,
    1146             :                  header, footer, ex);
    1147             : 
    1148             :   } else {
    1149           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
    1150             :   }
    1151             : 
    1152           0 :   if (!ok) {
    1153           0 :     return false; // either encrypt() or authtag() already set 'ex'
    1154             :   }
    1155             : 
    1156           0 :   size_t size = serialized_size(common_encoding, header);
    1157             : 
    1158           0 :   if (pOut != &plain_buffer) {
    1159           0 :     size += CRYPTO_CONTENT_ADDED_LENGTH;
    1160             :   }
    1161             : 
    1162           0 :   size += pOut->length();
    1163           0 :   serialized_size(common_encoding, size, footer);
    1164             : 
    1165           0 :   encoded_buffer.length(static_cast<unsigned int>(size));
    1166           0 :   ACE_Message_Block mb(to_mb(encoded_buffer.get_buffer()), size);
    1167           0 :   Serializer ser(&mb, common_encoding);
    1168           0 :   ser << header;
    1169             : 
    1170           0 :   if (pOut != &plain_buffer) {
    1171           0 :     ser << pOut->length();
    1172             :   }
    1173           0 :   ser.write_octet_array(pOut->get_buffer(), pOut->length());
    1174             : 
    1175           0 :   ser << footer;
    1176           0 :   return ser.good_bit();
    1177           2 : }
    1178             : 
    1179           0 : void CryptoBuiltInImpl::Session::create_key(const KeyMaterial& master)
    1180             : {
    1181           0 :   RAND_bytes(id_, sizeof id_);
    1182           0 :   RAND_bytes(iv_suffix_, sizeof iv_suffix_);
    1183           0 :   derive_key(master);
    1184           0 :   counter_ = 0;
    1185           0 : }
    1186             : 
    1187           0 : void CryptoBuiltInImpl::Session::next_id(const KeyMaterial& master)
    1188             : {
    1189           0 :   inc32(id_);
    1190           0 :   RAND_bytes(iv_suffix_, sizeof iv_suffix_);
    1191           0 :   key_.length(0);
    1192           0 :   derive_key(master);
    1193           0 :   counter_ = 0;
    1194           0 : }
    1195             : 
    1196           0 : void CryptoBuiltInImpl::Session::inc_iv()
    1197             : {
    1198           0 :   if (inc32(iv_suffix_)) {
    1199           0 :     inc32(iv_suffix_ + 4);
    1200             :   }
    1201           0 : }
    1202             : 
    1203           0 : void CryptoBuiltInImpl::encauth_setup(const KeyMaterial& master, Session& sess,
    1204             :                                       const DDS::OctetSeq& plain,
    1205             :                                       CryptoHeader& header)
    1206             : {
    1207             :   const unsigned int blocks =
    1208           0 :     (plain.length() + BLOCK_LEN_BYTES - 1) / BLOCK_LEN_BYTES;
    1209             : 
    1210           0 :   if (!sess.key_.length()) {
    1211           0 :     sess.create_key(master);
    1212             : 
    1213           0 :   } else if (sess.counter_ + blocks > MAX_BLOCKS_PER_SESSION) {
    1214           0 :     sess.next_id(master);
    1215             : 
    1216             :   } else {
    1217           0 :     sess.inc_iv();
    1218           0 :     sess.counter_ += blocks;
    1219             :   }
    1220             : 
    1221           0 :   std::memcpy(&header.transform_identifier.transformation_kind,
    1222           0 :               &master.transformation_kind, sizeof master.transformation_kind);
    1223           0 :   std::memcpy(&header.transform_identifier.transformation_key_id,
    1224           0 :               &master.sender_key_id, sizeof master.sender_key_id);
    1225           0 :   std::memcpy(&header.session_id, &sess.id_, sizeof sess.id_);
    1226           0 :   std::memcpy(&header.initialization_vector_suffix, &sess.iv_suffix_, sizeof sess.iv_suffix_);
    1227           0 : }
    1228             : 
    1229           0 : bool CryptoBuiltInImpl::encrypt(const KeyMaterial& master, Session& sess,
    1230             :                                 const DDS::OctetSeq& plain,
    1231             :                                 CryptoHeader& header, CryptoFooter& footer,
    1232             :                                 DDS::OctetSeq& out, SecurityException& ex)
    1233             : {
    1234           0 :   if (security_debug.showkeys) {
    1235           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} CryptoBuiltInImpl::encrypt: ")
    1236             :       ACE_TEXT("Using this key to encrypt:\n%C"),
    1237             :       to_dds_string(master).c_str()));
    1238             :   }
    1239             : 
    1240           0 :   encauth_setup(master, sess, plain, header);
    1241             :   static const int IV_LEN = 12, IV_SUFFIX_IDX = 4;
    1242             :   unsigned char iv[IV_LEN];
    1243           0 :   std::memcpy(iv, &sess.id_, sizeof sess.id_);
    1244           0 :   std::memcpy(iv + IV_SUFFIX_IDX, &sess.iv_suffix_, sizeof sess.iv_suffix_);
    1245             : 
    1246           0 :   if (security_debug.fake_encryption) {
    1247           0 :     out = plain;
    1248           0 :     return true;
    1249             :   }
    1250             : 
    1251           0 :   CipherContext ctx;
    1252           0 :   const unsigned char* const key = sess.key_.get_buffer();
    1253           0 :   if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), 0, key, iv) != 1) {
    1254           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptInit_ex");
    1255             :   }
    1256             : 
    1257             :   int len;
    1258           0 :   out.length(plain.length() + BLOCK_LEN_BYTES - 1);
    1259           0 :   unsigned char* const out_buffer = out.get_buffer();
    1260           0 :   if (EVP_EncryptUpdate(ctx, out_buffer, &len,
    1261           0 :                         plain.get_buffer(), plain.length()) != 1) {
    1262           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptUpdate");
    1263             :   }
    1264             : 
    1265             :   int padLen;
    1266           0 :   if (EVP_EncryptFinal_ex(ctx, out_buffer + len, &padLen) != 1) {
    1267           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptFinal_ex");
    1268             :   }
    1269             : 
    1270           0 :   out.length(len + padLen);
    1271             : 
    1272           0 :   if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, sizeof footer.common_mac,
    1273           0 :                           &footer.common_mac) != 1) {
    1274           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
    1275             :   }
    1276             : 
    1277           0 :   return true;
    1278           0 : }
    1279             : 
    1280           0 : bool CryptoBuiltInImpl::authtag(const KeyMaterial& master, Session& sess,
    1281             :                                 const DDS::OctetSeq& plain,
    1282             :                                 CryptoHeader& header,
    1283             :                                 CryptoFooter& footer,
    1284             :                                 SecurityException& ex)
    1285             : {
    1286           0 :   encauth_setup(master, sess, plain, header);
    1287             :   static const int IV_LEN = 12, IV_SUFFIX_IDX = 4;
    1288             :   unsigned char iv[IV_LEN];
    1289           0 :   std::memcpy(iv, &sess.id_, sizeof sess.id_);
    1290           0 :   std::memcpy(iv + IV_SUFFIX_IDX, &sess.iv_suffix_, sizeof sess.iv_suffix_);
    1291             : 
    1292           0 :   CipherContext ctx;
    1293           0 :   const unsigned char* const key = sess.key_.get_buffer();
    1294           0 :   if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), 0, key, iv) != 1) {
    1295           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptInit_ex");
    1296             :   }
    1297             : 
    1298             :   int n;
    1299           0 :   if (EVP_EncryptUpdate(ctx, 0, &n, plain.get_buffer(), plain.length()) != 1) {
    1300           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptUpdate");
    1301             :   }
    1302             : 
    1303           0 :   if (EVP_EncryptFinal_ex(ctx, 0, &n) != 1) {
    1304           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptFinal_ex");
    1305             :   }
    1306             : 
    1307           0 :   if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, sizeof footer.common_mac,
    1308           0 :                           &footer.common_mac) != 1) {
    1309           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
    1310             :   }
    1311             : 
    1312           0 :   return true;
    1313           0 : }
    1314             : 
    1315             : namespace {
    1316             :   // Precondition: the bytes of 'plaintext' are a sequence of RTPS Submessages
    1317             :   // Returns the index of the final Submessage in the sequence, or 0 if this can't be determined.
    1318           0 :   unsigned int findLastSubmessage(const DDS::OctetSeq& plaintext)
    1319             :   {
    1320           0 :     RTPS::MessageParser parser(plaintext);
    1321           0 :     const char* const start = parser.current();
    1322             : 
    1323           0 :     while (parser.remaining() >= RTPS::SMHDR_SZ) {
    1324           0 :       const unsigned int sm_start = static_cast<unsigned int>(parser.current() - start);
    1325             : 
    1326           0 :       if (!parser.parseSubmessageHeader()) {
    1327           0 :         return 0;
    1328             :       }
    1329             : 
    1330           0 :       if (!parser.hasNextSubmessage()) {
    1331           0 :         return sm_start;
    1332             :       }
    1333             : 
    1334           0 :       parser.skipToNextSubmessage();
    1335             :     }
    1336             : 
    1337           0 :     return 0;
    1338           0 :   }
    1339             : 
    1340           0 :   unsigned int roundUp(unsigned int length, unsigned int alignment)
    1341             :   {
    1342           0 :     const unsigned int offset = length % alignment;
    1343           0 :     return length + (offset ? alignment - offset : 0);
    1344             :   }
    1345             : 
    1346             :   const int SEQLEN_SZ = 4;
    1347             : 
    1348             :   // Precondition: the bytes of 'original' starting at 'offset' to the end of 'original' are a valid Submessage
    1349             :   // If that Submessage has octetsToNextHeader == 0, returns true and makes 'modified' a copy of 'original'
    1350             :   // with the Submessage's octetsToNextHeader set to the actual byte count from the end of its SubmessageHeader
    1351             :   // to the end of 'original', rounded up to the alignment requirements (4 bytes). Otherwise returns false.
    1352           0 :   bool setOctetsToNextHeader(DDS::OctetSeq& modified, const DDS::OctetSeq& original, unsigned int offset = 0)
    1353             :   {
    1354           0 :     if (offset + RTPS::SMHDR_SZ >= original.length()) {
    1355           0 :       return false;
    1356             :     }
    1357             : 
    1358           0 :     const size_t origLength = original.length() - offset;
    1359           0 :     ACE_Message_Block mb_in(to_mb(original.get_buffer() + offset), origLength);
    1360           0 :     mb_in.wr_ptr(origLength);
    1361             : 
    1362           0 :     Serializer ser_in(&mb_in, common_encoding);
    1363           0 :     ser_in.skip(1); // submessageId
    1364             : 
    1365             :     unsigned char flags;
    1366           0 :     ser_in >> ACE_InputCDR::to_octet(flags);
    1367           0 :     const int flag_e = flags & RTPS::FLAG_E;
    1368           0 :     ser_in.swap_bytes(ACE_CDR_BYTE_ORDER != flag_e);
    1369             : 
    1370             :     ACE_UINT16 submessageLength;
    1371           0 :     ser_in >> submessageLength;
    1372           0 :     if (submessageLength == 0) {
    1373           0 :       modified = original;
    1374           0 :       const size_t len = roundUp(static_cast<unsigned int>(origLength - RTPS::SMHDR_SZ), RTPS::SM_ALIGN);
    1375           0 :       modified[offset + 2 + !flag_e] = len & 0xff;
    1376           0 :       modified[offset + 2 + flag_e] = (len >> 8) & 0xff;
    1377           0 :       return true;
    1378             :     }
    1379           0 :     return false;
    1380           0 :   }
    1381             : }
    1382             : 
    1383           2 : bool CryptoBuiltInImpl::encode_submessage(
    1384             :   DDS::OctetSeq& encoded_rtps_submessage,
    1385             :   const DDS::OctetSeq& plain_rtps_submessage,
    1386             :   NativeCryptoHandle sender_handle,
    1387             :   SecurityException& ex)
    1388             : {
    1389           2 :   const KeyTable_t::const_iterator iter = keys_.find(sender_handle);
    1390           2 :   if (iter == keys_.end()) {
    1391           2 :     encoded_rtps_submessage = plain_rtps_submessage;
    1392           2 :     return true;
    1393             :   }
    1394             : 
    1395           0 :   const KeySeq& keyseq = iter->second;
    1396           0 :   if (!keyseq.length()) {
    1397           0 :     encoded_rtps_submessage = plain_rtps_submessage;
    1398           0 :     return true;
    1399             :   }
    1400             : 
    1401             :   bool ok;
    1402             :   CryptoHeader header;
    1403           0 :   CryptoFooter footer;
    1404           0 :   DDS::OctetSeq out;
    1405           0 :   const DDS::OctetSeq* pOut = &plain_rtps_submessage;
    1406           0 :   const KeyId_t sKey = std::make_pair(sender_handle, submessage_key_index);
    1407           0 :   bool authOnly = false;
    1408             : 
    1409           0 :   if (encrypts(keyseq[submessage_key_index])) {
    1410           0 :     ok = encrypt(keyseq[submessage_key_index], sessions_[sKey], plain_rtps_submessage,
    1411             :                  header, footer, out, ex);
    1412           0 :     pOut = &out;
    1413             : 
    1414           0 :   } else if (authenticates(keyseq[submessage_key_index])) {
    1415             :     // the original submessage may have octetsToNextHeader = 0 which isn't
    1416             :     // legal when appending SEC_POSTFIX, patch in the actual submsg length
    1417           0 :     if (setOctetsToNextHeader(out, plain_rtps_submessage)) {
    1418           0 :       pOut = &out;
    1419             :     }
    1420           0 :     ok = authtag(keyseq[submessage_key_index], sessions_[sKey], *pOut,
    1421             :                  header, footer, ex);
    1422           0 :     authOnly = true;
    1423             : 
    1424             :   } else {
    1425           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
    1426             :   }
    1427             : 
    1428           0 :   if (!ok) {
    1429           0 :     return false; // either encrypt() or authtag() already set 'ex'
    1430             :   }
    1431             : 
    1432           0 :   size_t size = 0;
    1433             : 
    1434           0 :   size += RTPS::SMHDR_SZ; // prefix submessage header
    1435           0 :   serialized_size(common_encoding, size, header);
    1436           0 :   const ACE_UINT16 hdrLen = static_cast<ACE_UINT16>(size - RTPS::SMHDR_SZ);
    1437             : 
    1438           0 :   if (!authOnly) {
    1439           0 :     size += RTPS::SMHDR_SZ + SEQLEN_SZ;
    1440             :   }
    1441             : 
    1442           0 :   size += pOut->length(); // submessage inside wrapper
    1443           0 :   align(size, RTPS::SM_ALIGN);
    1444             : 
    1445           0 :   size += RTPS::SMHDR_SZ; // postfix submessage header
    1446           0 :   const size_t preFooter = size;
    1447           0 :   serialized_size(common_encoding, size, footer);
    1448             : 
    1449           0 :   encoded_rtps_submessage.length(static_cast<unsigned int>(size));
    1450           0 :   ACE_Message_Block mb(to_mb(encoded_rtps_submessage.get_buffer()), size);
    1451           0 :   Serializer ser(&mb, common_encoding);
    1452           0 :   RTPS::SubmessageHeader smHdr = {RTPS::SEC_PREFIX, 0, hdrLen};
    1453           0 :   ser << smHdr;
    1454           0 :   ser << header;
    1455             : 
    1456           0 :   if (!authOnly) {
    1457           0 :     smHdr.submessageId = RTPS::SEC_BODY;
    1458           0 :     smHdr.submessageLength = static_cast<ACE_UINT16>(roundUp(SEQLEN_SZ + pOut->length(), RTPS::SM_ALIGN));
    1459           0 :     ser << smHdr;
    1460           0 :     ser << pOut->length();
    1461             :   }
    1462             : 
    1463           0 :   ser.write_octet_array(pOut->get_buffer(), pOut->length());
    1464           0 :   ser.align_w(RTPS::SM_ALIGN);
    1465             : 
    1466           0 :   smHdr.submessageId = RTPS::SEC_POSTFIX;
    1467           0 :   smHdr.submessageLength = static_cast<ACE_UINT16>(size - preFooter);
    1468           0 :   ser << smHdr;
    1469           0 :   ser << footer;
    1470             : 
    1471           0 :   return ser.good_bit();
    1472           0 : }
    1473             : 
    1474          23 : bool CryptoBuiltInImpl::encode_datawriter_submessage(
    1475             :   DDS::OctetSeq& encoded_rtps_submessage,
    1476             :   const DDS::OctetSeq& plain_rtps_submessage,
    1477             :   DatawriterCryptoHandle sending_datawriter_crypto,
    1478             :   const DatareaderCryptoHandleSeq& receiving_datareader_crypto_list,
    1479             :   CORBA::Long& receiving_datareader_crypto_list_index,
    1480             :   SecurityException& ex)
    1481             : {
    1482          23 :   if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
    1483           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataWriter handle");
    1484             :   }
    1485             : 
    1486          22 :   if (receiving_datareader_crypto_list_index < 0) {
    1487           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Negative list index");
    1488             :   }
    1489             : 
    1490          21 :   const int len = static_cast<int>(receiving_datareader_crypto_list.length());
    1491             :   // NOTE: as an extension to the spec, this plugin allows an empty list in the
    1492             :   // case where the writer is sending to all associated readers.
    1493          21 :   if (len && receiving_datareader_crypto_list_index >= len) {
    1494           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "List index too large");
    1495             :   }
    1496             : 
    1497         165 :   for (unsigned int i = 0; i < receiving_datareader_crypto_list.length(); ++i) {
    1498         155 :     if (receiving_datareader_crypto_list[i] == DDS::HANDLE_NIL) {
    1499          10 :       return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataReader handle in list");
    1500             :     }
    1501             :   }
    1502             : 
    1503          10 :   NativeCryptoHandle encode_handle = sending_datawriter_crypto;
    1504          10 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1505          10 :   const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(encode_handle);
    1506          10 :   if (eo_iter == encrypt_options_.end()) {
    1507           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
    1508             :   }
    1509             : 
    1510          10 :   if (!eo_iter->second.submessage_) {
    1511          10 :     encoded_rtps_submessage = plain_rtps_submessage;
    1512          10 :     receiving_datareader_crypto_list_index = len;
    1513          10 :     return true;
    1514             :   }
    1515             : 
    1516           0 :   if (receiving_datareader_crypto_list.length() == 1) {
    1517           0 :     const KeyTable_t::const_iterator iter = keys_.find(encode_handle);
    1518           0 :     if (iter != keys_.end()) {
    1519           0 :       const KeySeq& dw_keys = iter->second;
    1520           0 :       if (dw_keys.length() == 1 && is_volatile_placeholder(dw_keys[0])) {
    1521           0 :         encode_handle = receiving_datareader_crypto_list[0];
    1522             :       }
    1523             :     }
    1524             :   }
    1525             : 
    1526           0 :   const bool ok = encode_submessage(encoded_rtps_submessage,
    1527             :                                     plain_rtps_submessage, encode_handle, ex);
    1528           0 :   if (ok) {
    1529           0 :     receiving_datareader_crypto_list_index = len;
    1530             :   }
    1531           0 :   return ok;
    1532          10 : }
    1533             : 
    1534           3 : bool CryptoBuiltInImpl::encode_datareader_submessage(
    1535             :   DDS::OctetSeq& encoded_rtps_submessage,
    1536             :   const DDS::OctetSeq& plain_rtps_submessage,
    1537             :   DatareaderCryptoHandle sending_datareader_crypto,
    1538             :   const DatawriterCryptoHandleSeq& receiving_datawriter_crypto_list,
    1539             :   SecurityException& ex)
    1540             : {
    1541           3 :   if (DDS::HANDLE_NIL == sending_datareader_crypto) {
    1542           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataReader handle");
    1543             :   }
    1544             : 
    1545           8 :   for (unsigned int i = 0; i < receiving_datawriter_crypto_list.length(); ++i) {
    1546           6 :     if (receiving_datawriter_crypto_list[i] == DDS::HANDLE_NIL) {
    1547           0 :       return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataWriter handle in list");
    1548             :     }
    1549             :   }
    1550             : 
    1551           2 :   NativeCryptoHandle encode_handle = sending_datareader_crypto;
    1552           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1553           2 :   if (receiving_datawriter_crypto_list.length() == 1) {
    1554           1 :     const KeyTable_t::const_iterator iter = keys_.find(encode_handle);
    1555           1 :     if (iter != keys_.end()) {
    1556           0 :       const KeySeq& dr_keys = iter->second;
    1557           0 :       if (dr_keys.length() == 1 && is_volatile_placeholder(dr_keys[0])) {
    1558           0 :         encode_handle = receiving_datawriter_crypto_list[0];
    1559             :       }
    1560             :     }
    1561             :   }
    1562             : 
    1563           2 :   return encode_submessage(encoded_rtps_submessage, plain_rtps_submessage,
    1564           2 :                            encode_handle, ex);
    1565           2 : }
    1566             : 
    1567           3 : bool CryptoBuiltInImpl::encode_rtps_message(
    1568             :   DDS::OctetSeq& encoded_rtps_message,
    1569             :   const DDS::OctetSeq& plain_rtps_message,
    1570             :   ParticipantCryptoHandle sending_participant_crypto,
    1571             :   const ParticipantCryptoHandleSeq& receiving_participant_crypto_list,
    1572             :   CORBA::Long& receiving_participant_crypto_list_index,
    1573             :   SecurityException& ex)
    1574             : {
    1575           3 :   receiving_participant_crypto_list_index = receiving_participant_crypto_list.length();
    1576           3 :   if (DDS::HANDLE_NIL == sending_participant_crypto) {
    1577             :     // DDS-Security v1.1 8.5.1.9.4
    1578             :     // This operation may optionally not perform any transformation of the input RTPS message.
    1579             :     // In this case, the operation shall return false but not set the exception object.
    1580           1 :     return false;
    1581             :   }
    1582             : 
    1583           2 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1584           2 :   const KeyTable_t::const_iterator iter = keys_.find(sending_participant_crypto);
    1585           2 :   if (iter == keys_.end()) {
    1586           2 :     return CommonUtilities::set_security_error(ex, -1, 0, "No entry for sending_participant_crypto");
    1587             :   }
    1588             : 
    1589           0 :   const KeySeq& keyseq = iter->second;
    1590           0 :   if (!keyseq.length()) {
    1591           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "No key for sending_participant_crypto");
    1592             :   }
    1593             : 
    1594             :   // The input with its RTPS Header changed to an InfoSrc submessage acts as plaintext for encrypt/authenticate
    1595           0 :   DDS::OctetSeq transformed(plain_rtps_message.length() + RTPS::SMHDR_SZ);
    1596           0 :   transformed.length(transformed.maximum());
    1597           0 :   transformed[0] = RTPS::INFO_SRC;
    1598           0 :   transformed[1] = 0; // flags: big-endian
    1599           0 :   transformed[2] = 0; // high byte of octetsToNextHeader
    1600           0 :   transformed[3] = RTPS::INFO_SRC_SZ;
    1601           0 :   std::memcpy(transformed.get_buffer() + RTPS::SMHDR_SZ, plain_rtps_message.get_buffer(), plain_rtps_message.length());
    1602             : 
    1603           0 :   bool ok, addSecBody = false;
    1604             :   CryptoHeader cryptoHdr;
    1605           0 :   CryptoFooter cryptoFooter;
    1606           0 :   DDS::OctetSeq out;
    1607           0 :   const DDS::OctetSeq* pOut = &transformed;
    1608           0 :   const KeyMaterial& key = keyseq[0];
    1609           0 :   const KeyId_t sKey = std::make_pair(sending_participant_crypto, 0);
    1610             : 
    1611           0 :   if (encrypts(key)) {
    1612           0 :     ok = encrypt(key, sessions_[sKey], transformed, cryptoHdr, cryptoFooter, out, ex);
    1613           0 :     pOut = &out;
    1614           0 :     addSecBody = true;
    1615             : 
    1616           0 :   } else if (authenticates(key)) {
    1617             :     // the original message's last submsg may have octetsToNextHeader = 0 which
    1618             :     // isn't valid when appending SEC_POSTFIX, patch in the actual submsg length
    1619           0 :     const unsigned int offsetFinal = findLastSubmessage(transformed);
    1620           0 :     if (offsetFinal && setOctetsToNextHeader(out, transformed, offsetFinal)) {
    1621           0 :       pOut = &out;
    1622             :     }
    1623           0 :     ok = authtag(key, sessions_[sKey], *pOut, cryptoHdr, cryptoFooter, ex);
    1624             : 
    1625             :   } else {
    1626           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
    1627             :   }
    1628             : 
    1629           0 :   if (!ok) {
    1630           0 :     return false; // either encrypt() or authtag() already set 'ex'
    1631             :   }
    1632             : 
    1633           0 :   size_t size = RTPS::RTPSHDR_SZ + RTPS::SMHDR_SZ; // RTPS Header, SRTPS Prefix
    1634           0 :   serialized_size(common_encoding, size, cryptoHdr);
    1635           0 :   const ACE_UINT16 cryptoHdrLen =
    1636           0 :     static_cast<ACE_UINT16>(size - RTPS::RTPSHDR_SZ - RTPS::SMHDR_SZ);
    1637             : 
    1638           0 :   if (addSecBody) {
    1639           0 :     size += RTPS::SMHDR_SZ + SEQLEN_SZ;
    1640             :   }
    1641             : 
    1642           0 :   size += pOut->length();
    1643           0 :   align(size, RTPS::SM_ALIGN);
    1644             : 
    1645           0 :   size += RTPS::SMHDR_SZ; // SRTPS Postfix
    1646           0 :   serialized_size(common_encoding, size, cryptoFooter);
    1647             : 
    1648           0 :   encoded_rtps_message.length(static_cast<unsigned int>(size));
    1649           0 :   ACE_Message_Block mb(to_mb(encoded_rtps_message.get_buffer()), size);
    1650           0 :   Serializer ser(&mb, common_encoding);
    1651             : 
    1652           0 :   ser.write_octet_array(plain_rtps_message.get_buffer(), RTPS::RTPSHDR_SZ);
    1653             : 
    1654           0 :   RTPS::SubmessageHeader smHdr = {RTPS::SRTPS_PREFIX, 0, cryptoHdrLen};
    1655           0 :   ser << smHdr;
    1656           0 :   ser << cryptoHdr;
    1657             : 
    1658           0 :   if (addSecBody) {
    1659           0 :     smHdr.submessageId = RTPS::SEC_BODY;
    1660           0 :     smHdr.submessageLength = static_cast<ACE_UINT16>(roundUp(SEQLEN_SZ + pOut->length(), RTPS::SM_ALIGN));
    1661           0 :     ser << smHdr;
    1662           0 :     ser << pOut->length();
    1663             :   }
    1664             : 
    1665           0 :   ser.write_octet_array(pOut->get_buffer(), pOut->length());
    1666           0 :   ser.align_w(RTPS::SM_ALIGN);
    1667             : 
    1668           0 :   smHdr.submessageId = RTPS::SRTPS_POSTFIX;
    1669           0 :   smHdr.submessageLength = 0; // final submessage doesn't need a length
    1670           0 :   ser << smHdr;
    1671           0 :   ser << cryptoFooter;
    1672             : 
    1673           0 :   return ser.good_bit();
    1674           2 : }
    1675             : 
    1676             : namespace {
    1677           0 :   bool matches(const KeyMaterial_AES_GCM_GMAC& k, const CryptoHeader& h)
    1678             :   {
    1679           0 :     return 0 == std::memcmp(k.transformation_kind,
    1680           0 :                             h.transform_identifier.transformation_kind,
    1681             :                             sizeof(CryptoTransformKind))
    1682           0 :       && 0 == std::memcmp(k.sender_key_id,
    1683           0 :                           h.transform_identifier.transformation_key_id,
    1684           0 :                           sizeof(CryptoTransformKeyId));
    1685             :   }
    1686             : }
    1687             : 
    1688           3 : bool CryptoBuiltInImpl::preprocess_secure_submsg(
    1689             :   DatawriterCryptoHandle& datawriter_crypto,
    1690             :   DatareaderCryptoHandle& datareader_crypto,
    1691             :   SecureSubmessageCategory_t& secure_submessage_category,
    1692             :   const DDS::OctetSeq& encoded_rtps_submessage,
    1693             :   ParticipantCryptoHandle,
    1694             :   ParticipantCryptoHandle sending_participant_crypto,
    1695             :   SecurityException& ex)
    1696             : {
    1697           3 :   if (DDS::HANDLE_NIL == sending_participant_crypto) {
    1698           2 :     CommonUtilities::set_security_error(ex, -1, 0, "Invalid Sending Participant");
    1699           2 :     return false;
    1700             :   }
    1701             : 
    1702             :   ACE_Message_Block mb_in(to_mb(encoded_rtps_submessage.get_buffer()),
    1703           1 :                           encoded_rtps_submessage.length());
    1704           1 :   mb_in.wr_ptr(encoded_rtps_submessage.length());
    1705           1 :   Serializer de_ser(&mb_in, common_encoding);
    1706           1 :   CryptoHeader ch = CryptoHeader();
    1707           1 :   if (!(de_ser.skip(RTPS::SMHDR_SZ) && (de_ser >> ch))) {
    1708           1 :     ACE_ERROR((LM_ERROR,
    1709             :       "(%P|%t) CryptoBuiltInImpl::preprocess_secure_submsg: "
    1710             :       "Could not deserializer CyptoHeader\n"));
    1711             :   }
    1712             : 
    1713           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    1714             :   typedef std::multimap<ParticipantCryptoHandle, EntityInfo>::iterator iter_t;
    1715             :   const std::pair<iter_t, iter_t> iters =
    1716           1 :     participant_to_entity_.equal_range(sending_participant_crypto);
    1717           1 :   if (security_debug.chlookup) {
    1718           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
    1719             :       ACE_TEXT("Looking for CH that matches transformation id:\n%C"),
    1720             :       to_dds_string(ch.transform_identifier).c_str()));
    1721             :   }
    1722           1 :   for (iter_t iter = iters.first; iter != iters.second; ++iter) {
    1723           0 :     const NativeCryptoHandle sending_entity_candidate = iter->second.handle_;
    1724           0 :     const KeyTable_t::const_iterator kiter = keys_.find(sending_entity_candidate);
    1725           0 :     if (security_debug.chlookup) {
    1726           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
    1727             :         ACE_TEXT("  Looking at CH %u, has keys: %C\n"),
    1728             :         sending_entity_candidate, kiter == keys_.end() ? "false" : "true"));
    1729             :     }
    1730           0 :     if (kiter != keys_.end()) {
    1731           0 :       const KeySeq& keyseq = kiter->second;
    1732           0 :       const unsigned keycount = keyseq.length();
    1733           0 :       if (security_debug.chlookup) {
    1734           0 :         ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
    1735             :           ACE_TEXT("  Number of keys: %u\n"), keycount));
    1736             :       }
    1737           0 :       for (unsigned int i = 0; i < keycount; ++i) {
    1738           0 :         if (security_debug.chlookup) {
    1739           0 :           ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
    1740             :             ACE_TEXT("    Key: %C\n"),
    1741             :             (OPENDDS_STRING(ctk_to_dds_string(keyseq[i].transformation_kind)) + ", " +
    1742             :               ctki_to_dds_string(keyseq[i].sender_key_id)).c_str()));
    1743             :         }
    1744           0 :         if (matches(keyseq[i], ch)) {
    1745           0 :           char chtype = '\0';
    1746           0 :           secure_submessage_category = iter->second.category_;
    1747           0 :           switch (secure_submessage_category) {
    1748           0 :           case DATAWRITER_SUBMESSAGE:
    1749           0 :             datawriter_crypto = iter->second.handle_;
    1750           0 :             chtype = 'W';
    1751           0 :             break;
    1752           0 :           case DATAREADER_SUBMESSAGE:
    1753           0 :             datareader_crypto = iter->second.handle_;
    1754           0 :             chtype = 'R';
    1755           0 :             break;
    1756           0 :           default:
    1757           0 :             break;
    1758             :           }
    1759           0 :           if (security_debug.chlookup && chtype) {
    1760           0 :             ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
    1761             :               ACE_TEXT("D%cCH Found!\n"), chtype));
    1762             :           }
    1763           0 :           return true;
    1764             :         }
    1765             :       }
    1766             :     }
    1767             :   }
    1768           1 :   CommonUtilities::set_security_error(ex, -2, 1, "Crypto Key not registered",
    1769             :                                       ch.transform_identifier.transformation_kind,
    1770             :                                       ch.transform_identifier.transformation_key_id);
    1771           1 :   return false;
    1772           1 : }
    1773             : 
    1774             : KeyOctetSeq
    1775           0 : CryptoBuiltInImpl::Session::get_key(const KeyMaterial& master,
    1776             :                                     const CryptoHeader& header)
    1777             : {
    1778           0 :   if (key_.length() && 0 == std::memcmp(&id_, &header.session_id, sizeof id_)) {
    1779           0 :     return key_;
    1780             :   }
    1781           0 :   std::memcpy(&id_, &header.session_id, sizeof id_);
    1782           0 :   key_.length(0);
    1783           0 :   derive_key(master);
    1784           0 :   return key_;
    1785             : }
    1786             : 
    1787           0 : void CryptoBuiltInImpl::Session::derive_key(const KeyMaterial& master)
    1788             : {
    1789           0 :   PrivateKey pkey(master.master_sender_key);
    1790           0 :   DigestContext ctx;
    1791           0 :   const EVP_MD* md = EVP_get_digestbyname("SHA256");
    1792             : 
    1793           0 :   if (EVP_DigestInit_ex(ctx, md, 0) < 1) {
    1794           0 :     return;
    1795             :   }
    1796             : 
    1797           0 :   if (EVP_DigestSignInit(ctx, 0, md, 0, pkey) < 1) {
    1798           0 :     return;
    1799             :   }
    1800             : 
    1801             :   static const char cookie[] = "SessionKey"; // DDSSEC12-53: NUL excluded
    1802           0 :   if (EVP_DigestSignUpdate(ctx, cookie, (sizeof cookie) - 1) < 1) {
    1803           0 :     return;
    1804             :   }
    1805             : 
    1806           0 :   const KeyOctetSeq& salt = master.master_salt;
    1807           0 :   if (EVP_DigestSignUpdate(ctx, salt.get_buffer(), salt.length()) < 1) {
    1808           0 :     return;
    1809             :   }
    1810             : 
    1811           0 :   if (EVP_DigestSignUpdate(ctx, id_, sizeof id_) < 1) {
    1812           0 :     return;
    1813             :   }
    1814             : 
    1815           0 :   size_t req = 0;
    1816           0 :   if (EVP_DigestSignFinal(ctx, 0, &req) < 1) {
    1817           0 :     return;
    1818             :   }
    1819             : 
    1820           0 :   key_.length(static_cast<unsigned int>(req));
    1821           0 :   if (EVP_DigestSignFinal(ctx, key_.get_buffer(), &req) < 1) {
    1822           0 :     key_.length(0);
    1823             :   }
    1824           0 : }
    1825             : 
    1826           0 : bool CryptoBuiltInImpl::decrypt(const KeyMaterial& master, Session& sess,
    1827             :                                 const char* ciphertext, unsigned int n,
    1828             :                                 const CryptoHeader& header,
    1829             :                                 const CryptoFooter& footer, DDS::OctetSeq& out,
    1830             :                                 SecurityException& ex)
    1831             : 
    1832             : {
    1833           0 :   if (security_debug.showkeys) {
    1834           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {showkeys} CryptoBuiltInImpl::decrypt ")
    1835             :       ACE_TEXT("Using this key to decrypt:\n%C"),
    1836             :       to_dds_string(master).c_str()));
    1837             :   }
    1838             : 
    1839           0 :   const KeyOctetSeq sess_key = sess.get_key(master, header);
    1840           0 :   if (!sess_key.length()) {
    1841           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "no session key");
    1842             :   }
    1843             : 
    1844           0 :   if (master.transformation_kind[TransformKindIndex] !=
    1845             :       CRYPTO_TRANSFORMATION_KIND_AES256_GCM) {
    1846           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
    1847             :                "unsupported transformation kind %d\n",
    1848             :                master.transformation_kind[TransformKindIndex]));
    1849           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "unsupported transformation kind");
    1850             :   }
    1851             : 
    1852           0 :   if (security_debug.fake_encryption) {
    1853           0 :     out.length(n);
    1854           0 :     std::memcpy(out.get_buffer(), ciphertext, n);
    1855           0 :     return true;
    1856             :   }
    1857             : 
    1858           0 :   CipherContext ctx;
    1859             :   // session_id is start of IV contiguous bytes
    1860           0 :   if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), 0, sess_key.get_buffer(),
    1861           0 :                          header.session_id) != 1) {
    1862           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
    1863             :                "EVP_DecryptInit_ex %Ld\n", ERR_peek_last_error()));
    1864           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptInit_ex");
    1865             :   }
    1866             : 
    1867           0 :   out.length(n + KEY_LEN_BYTES);
    1868           0 :   unsigned char* const out_buffer = out.get_buffer();
    1869             :   int len;
    1870           0 :   if (EVP_DecryptUpdate(ctx, out_buffer, &len,
    1871             :                         reinterpret_cast<const unsigned char*>(ciphertext), n)
    1872           0 :       != 1) {
    1873           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
    1874             :                "EVP_DecryptUpdate %Ld\n", ERR_peek_last_error()));
    1875           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptUpdate");
    1876             :   }
    1877             : 
    1878           0 :   void* tag = const_cast<void*>(static_cast<const void*>(footer.common_mac));
    1879           0 :   if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
    1880           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
    1881             :                "EVP_CIPHER_CTX_ctrl %Ld\n", ERR_peek_last_error()));
    1882           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
    1883             :   }
    1884             : 
    1885             :   int len2;
    1886           0 :   if (EVP_DecryptFinal_ex(ctx, out_buffer + len, &len2) == 1) {
    1887           0 :     out.length(len + len2);
    1888           0 :     return true;
    1889             :   }
    1890           0 :   ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
    1891             :              "EVP_DecryptFinal_ex %Ld\n", ERR_peek_last_error()));
    1892           0 :   return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptFinal_ex");
    1893           0 : }
    1894             : 
    1895           0 : bool CryptoBuiltInImpl::verify(const KeyMaterial& master, Session& sess,
    1896             :                                const char* in, unsigned int n,
    1897             :                                const CryptoHeader& header,
    1898             :                                const CryptoFooter& footer, DDS::OctetSeq& out,
    1899             :                                SecurityException& ex)
    1900             : 
    1901             : {
    1902           0 :   const KeyOctetSeq sess_key = sess.get_key(master, header);
    1903           0 :   if (!sess_key.length()) {
    1904           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "no session key");
    1905             :   }
    1906             : 
    1907           0 :   if (master.transformation_kind[TransformKindIndex] !=
    1908             :       CRYPTO_TRANSFORMATION_KIND_AES256_GMAC) {
    1909           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
    1910             :                "unsupported transformation kind %d\n",
    1911             :                master.transformation_kind[TransformKindIndex]));
    1912           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "unsupported transformation kind");
    1913             :   }
    1914             : 
    1915           0 :   CipherContext ctx;
    1916             :   // session_id is start of IV contiguous bytes
    1917           0 :   if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), 0, sess_key.get_buffer(),
    1918           0 :                          header.session_id) != 1) {
    1919           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
    1920             :                "EVP_DecryptInit_ex %Ld\n", ERR_peek_last_error()));
    1921           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptInit_ex");
    1922             :   }
    1923             : 
    1924             :   int len;
    1925           0 :   if (EVP_DecryptUpdate(ctx, 0, &len,
    1926           0 :                         reinterpret_cast<const unsigned char*>(in), n) != 1) {
    1927           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
    1928             :                "EVP_DecryptUpdate %Ld\n", ERR_peek_last_error()));
    1929           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptUpdate");
    1930             :   }
    1931             : 
    1932           0 :   void* tag = const_cast<void*>(static_cast<const void*>(footer.common_mac));
    1933           0 :   if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
    1934           0 :     ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
    1935             :                "EVP_CIPHER_CTX_ctrl %Ld\n", ERR_peek_last_error()));
    1936           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
    1937             :   }
    1938             : 
    1939             :   int len2;
    1940           0 :   if (EVP_DecryptFinal_ex(ctx, 0, &len2) == 1) {
    1941           0 :     out.length(n);
    1942           0 :     std::memcpy(out.get_buffer(), in, n);
    1943           0 :     return true;
    1944             :   }
    1945           0 :   ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
    1946             :              "EVP_DecryptFinal_ex %Ld\n", ERR_peek_last_error()));
    1947           0 :   return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptFinal_ex");
    1948           0 : }
    1949             : 
    1950           3 : bool CryptoBuiltInImpl::decode_rtps_message(
    1951             :   DDS::OctetSeq& plain_buffer,
    1952             :   const DDS::OctetSeq& encoded_buffer,
    1953             :   ParticipantCryptoHandle receiving_participant_crypto,
    1954             :   ParticipantCryptoHandle sending_participant_crypto,
    1955             :   SecurityException& ex)
    1956             : {
    1957           3 :   if (DDS::HANDLE_NIL == receiving_participant_crypto) {
    1958           2 :     return CommonUtilities::set_security_error(ex, -1, 0, "No Receiving Participant handle");
    1959             :   }
    1960           1 :   if (DDS::HANDLE_NIL == sending_participant_crypto) {
    1961           1 :     return CommonUtilities::set_security_error(ex, -1, 1, "No Sending Participant handle");
    1962             :   }
    1963             : 
    1964           0 :   RTPS::MessageParser parser(encoded_buffer);
    1965             : 
    1966           0 :   if (!parser.parseHeader()) {
    1967           0 :     return CommonUtilities::set_security_error(ex, -2, 0, "Failed to deserialize Header");
    1968             :   }
    1969             : 
    1970           0 :   CryptoHeader ch = CryptoHeader();
    1971           0 :   CryptoFooter cf;
    1972           0 :   bool haveCryptoHeader = false, haveCryptoFooter = false;
    1973           0 :   const char* afterSrtpsPrefix = 0;
    1974             :   unsigned int sizeOfAuthenticated, sizeOfEncrypted;
    1975           0 :   const char* encrypted = 0;
    1976             : 
    1977           0 :   for (int i = 0; parser.remaining(); ++i) {
    1978           0 :     if (parser.remaining() < RTPS::SMHDR_SZ || !parser.parseSubmessageHeader()) {
    1979           0 :       return CommonUtilities::set_security_error(ex, -3, i, "Failed to deserialize SubmessageHeader");
    1980             :     }
    1981             : 
    1982           0 :     parser.serializer().endianness(ENDIAN_BIG);
    1983           0 :     const int type = parser.submessageHeader().submessageId;
    1984             : 
    1985           0 :     if (i == 0 && type == RTPS::SRTPS_PREFIX) {
    1986           0 :       if (!(parser >> ch)) {
    1987           0 :         return CommonUtilities::set_security_error(ex, -4, i, "Failed to deserialize CryptoHeader");
    1988             :       }
    1989           0 :       haveCryptoHeader = true;
    1990           0 :       if (!parser.skipToNextSubmessage()) {
    1991           0 :         return CommonUtilities::set_security_error(ex, -5, i, "Failed to find submessage after SRTPS_PREFIX");
    1992             :       }
    1993           0 :       afterSrtpsPrefix = parser.current();
    1994             : 
    1995           0 :     } else if (haveCryptoHeader && type == RTPS::SEC_BODY) {
    1996           0 :       if (!(parser >> sizeOfEncrypted)) {
    1997           0 :         return CommonUtilities::set_security_error(ex, -13, i, "Failed to deserialize CryptoContent length");
    1998             :       }
    1999           0 :       const unsigned short sz =
    2000             :         static_cast<unsigned short>(DCPS::uint32_cdr_size);
    2001           0 :       if (sizeOfEncrypted + sz > parser.submessageHeader().submessageLength) {
    2002           0 :         return CommonUtilities::set_security_error(ex, -14, i, "CryptoContent length out of bounds");
    2003             :       }
    2004           0 :       encrypted = parser.current();
    2005           0 :       if (!parser.skipToNextSubmessage()) {
    2006           0 :         return CommonUtilities::set_security_error(ex, -15, i, "Failed to find submessage after SEC_BODY");
    2007             :       }
    2008             : 
    2009           0 :     } else if (haveCryptoHeader && type == RTPS::SRTPS_POSTFIX) {
    2010           0 :       sizeOfAuthenticated = static_cast<unsigned int>(parser.current() - afterSrtpsPrefix - RTPS::SMHDR_SZ);
    2011           0 :       if (!(parser >> cf)) {
    2012           0 :         return CommonUtilities::set_security_error(ex, -7, i, "Failed to deserialize CryptoFooter");
    2013             :       }
    2014           0 :       if (parser.hasNextSubmessage()) {
    2015           0 :         return CommonUtilities::set_security_error(ex, -8, i, "SRTPS_POSTFIX was not the final submessage");
    2016             :       }
    2017           0 :       haveCryptoFooter = true;
    2018           0 :       break;
    2019             : 
    2020             :     } else {
    2021           0 :       if (parser.hasNextSubmessage()) {
    2022           0 :         if (!parser.skipToNextSubmessage()) {
    2023           0 :           return CommonUtilities::set_security_error(ex, -6, i, "Failed to find next submessage");
    2024             :         }
    2025             :       } else {
    2026           0 :         break;
    2027             :       }
    2028             :     }
    2029             :   }
    2030             : 
    2031           0 :   if (!haveCryptoHeader || !haveCryptoFooter) {
    2032           0 :     return CommonUtilities::set_security_error(ex, -9, 0, "Failed to find SRTPS_PREFIX/POSTFIX wrapper");
    2033             :   }
    2034             : 
    2035           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    2036           0 :   const KeyTable_t::const_iterator iter = keys_.find(sending_participant_crypto);
    2037           0 :   if (iter == keys_.end()) {
    2038           0 :     return CommonUtilities::set_security_error(ex, -1, 2, "No key for Sending Participant handle");
    2039             :   }
    2040           0 :   const KeySeq& keyseq = iter->second;
    2041           0 :   bool foundKey = false;
    2042           0 :   DDS::OctetSeq transformed;
    2043           0 :   for (unsigned int i = 0; !foundKey && i < keyseq.length(); ++i) {
    2044           0 :     if (matches(keyseq[i], ch)) {
    2045           0 :       const KeyId_t sKey = std::make_pair(sending_participant_crypto, i);
    2046             : 
    2047           0 :       if (encrypts(keyseq[i])) {
    2048           0 :         if (!encrypted) {
    2049           0 :           return CommonUtilities::set_security_error(ex, -15, 0, "Failed to find SEC_BODY submessage");
    2050             :         }
    2051           0 :         foundKey = true;
    2052           0 :         if (!decrypt(keyseq[i], sessions_[sKey], encrypted, sizeOfEncrypted,
    2053             :                      ch, cf, transformed, ex)) {
    2054           0 :           return false;
    2055             :         }
    2056             : 
    2057           0 :       } else if (authenticates(keyseq[i])) {
    2058           0 :         foundKey = true;
    2059           0 :         if (!verify(keyseq[i], sessions_[sKey], afterSrtpsPrefix, sizeOfAuthenticated,
    2060             :                     ch, cf, transformed, ex)) {
    2061           0 :           return false;
    2062             :         }
    2063             : 
    2064             :       } else {
    2065           0 :         return CommonUtilities::set_security_error(ex, -10, 2, "Key transform kind unrecognized");
    2066             :       }
    2067             :     }
    2068             :   }
    2069             : 
    2070           0 :   if (!foundKey) {
    2071           0 :     return CommonUtilities::set_security_error(ex, OPENDDS_EXCEPTION_CODE_NO_KEY,
    2072           0 :                                                OPENDDS_EXCEPTION_MINOR_CODE_NO_KEY, "Crypto Key not found");
    2073             :   }
    2074             : 
    2075           0 :   if (transformed.length() < RTPS::SMHDR_SZ + RTPS::INFO_SRC_SZ
    2076           0 :       || transformed[0] != RTPS::INFO_SRC) {
    2077           0 :     return CommonUtilities::set_security_error(ex, -11, 0, "Plaintext doesn't start with INFO_SRC");
    2078             :   }
    2079             : 
    2080             :   static const int GuidPrefixOffset = 8; // "RTPS", Version(2), Vendor(2)
    2081           0 :   if (std::memcmp(transformed.get_buffer() + RTPS::SMHDR_SZ + GuidPrefixOffset,
    2082           0 :                   encoded_buffer.get_buffer() + GuidPrefixOffset,
    2083             :                   sizeof(DCPS::GuidPrefix_t))) {
    2084           0 :     return CommonUtilities::set_security_error(ex, -12, 0, "Header GUID Prefix doesn't match INFO_SRC");
    2085             :   }
    2086             : 
    2087           0 :   plain_buffer.length(transformed.length() - RTPS::SMHDR_SZ);
    2088           0 :   std::memcpy(plain_buffer.get_buffer(), RTPS::PROTOCOL_RTPS, sizeof RTPS::PROTOCOL_RTPS);
    2089           0 :   std::memcpy(plain_buffer.get_buffer() + sizeof RTPS::PROTOCOL_RTPS,
    2090           0 :               transformed.get_buffer() + RTPS::SMHDR_SZ + sizeof RTPS::PROTOCOL_RTPS,
    2091           0 :               plain_buffer.length() - sizeof RTPS::PROTOCOL_RTPS);
    2092           0 :   return true;
    2093           0 : }
    2094             : 
    2095           0 : bool CryptoBuiltInImpl::decode_submessage(
    2096             :   DDS::OctetSeq& plain_rtps_submessage,
    2097             :   const DDS::OctetSeq& encoded_rtps_submessage,
    2098             :   NativeCryptoHandle sender_handle,
    2099             :   SecurityException& ex)
    2100             : {
    2101             :   ACE_Message_Block mb_in(to_mb(encoded_rtps_submessage.get_buffer()),
    2102           0 :                           encoded_rtps_submessage.length());
    2103           0 :   mb_in.wr_ptr(encoded_rtps_submessage.length());
    2104           0 :   Serializer de_ser(&mb_in, common_encoding);
    2105             :   ACE_CDR::Octet type, flags;
    2106             :   // SEC_PREFIX
    2107           0 :   de_ser >> ACE_InputCDR::to_octet(type);
    2108           0 :   de_ser >> ACE_InputCDR::to_octet(flags);
    2109           0 :   de_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
    2110             :   ACE_CDR::UShort octetsToNext;
    2111           0 :   de_ser >> octetsToNext;
    2112           0 :   CryptoHeader ch = CryptoHeader();
    2113           0 :   de_ser.endianness(ENDIAN_BIG);
    2114           0 :   de_ser >> ch;
    2115           0 :   de_ser.skip(octetsToNext - CRYPTO_HEADER_LENGTH);
    2116           0 :   if (!de_ser.good_bit()) {
    2117           0 :     ACE_ERROR((LM_ERROR,
    2118             :       "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
    2119             :       "Failed to deserialize SEC_PREFIX\n"));
    2120           0 :     return false;
    2121             :   }
    2122             : 
    2123             :   // Next submessage, SEC_BODY if encrypted
    2124           0 :   de_ser >> ACE_InputCDR::to_octet(type);
    2125           0 :   de_ser >> ACE_InputCDR::to_octet(flags);
    2126           0 :   de_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
    2127           0 :   de_ser >> octetsToNext;
    2128           0 :   if (!de_ser.good_bit()) {
    2129           0 :     ACE_ERROR((LM_ERROR,
    2130             :       "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
    2131             :       "Failed to deserialize next submessage\n"));
    2132           0 :     return false;
    2133             :   }
    2134             : 
    2135           0 :   Message_Block_Ptr mb_footer(mb_in.duplicate());
    2136           0 :   mb_footer->rd_ptr(octetsToNext);
    2137             :   // SEC_POSTFIX
    2138           0 :   Serializer post_ser(mb_footer.get(), common_encoding);
    2139           0 :   post_ser >> ACE_InputCDR::to_octet(type);
    2140           0 :   post_ser >> ACE_InputCDR::to_octet(flags);
    2141           0 :   post_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
    2142             :   ACE_CDR::UShort postfixOctetsToNext;
    2143           0 :   post_ser >> postfixOctetsToNext;
    2144           0 :   CryptoFooter cf;
    2145           0 :   de_ser.endianness(ENDIAN_BIG);
    2146           0 :   post_ser >> cf;
    2147           0 :   if (!post_ser.good_bit()) {
    2148           0 :     ACE_ERROR((LM_ERROR,
    2149             :       "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
    2150             :       "Failed to deserialize SEC_POST\n"));
    2151           0 :     return false;
    2152             :   }
    2153             : 
    2154           0 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    2155           0 :   const KeyTable_t::const_iterator keys_iter = keys_.find(sender_handle);
    2156           0 :   if (keys_iter == keys_.end()) {
    2157           0 :     return CommonUtilities::set_security_error(ex, -2, 3, "Crypto Key not found");
    2158             :   }
    2159             : 
    2160           0 :   const KeySeq& keyseq = keys_iter->second;
    2161           0 :   for (unsigned int i = 0; i < keyseq.length(); ++i) {
    2162           0 :     if (matches(keyseq[i], ch)) {
    2163           0 :       const KeyId_t sKey = std::make_pair(sender_handle, i);
    2164             : 
    2165           0 :       if (encrypts(keyseq[i])) {
    2166           0 :         de_ser.endianness(ENDIAN_BIG);
    2167             :         ACE_CDR::ULong n;
    2168           0 :         if (!(de_ser >> n)) {
    2169           0 :           ACE_ERROR((LM_ERROR,
    2170             :             "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
    2171             :             "Failed to deserialize content size(?)\n"));
    2172           0 :           return false;
    2173             :         }
    2174           0 :         return decrypt(keyseq[i], sessions_[sKey], mb_in.rd_ptr(), n, ch, cf,
    2175           0 :                        plain_rtps_submessage, ex);
    2176             : 
    2177           0 :       } else if (authenticates(keyseq[i])) {
    2178           0 :         return verify(keyseq[i], sessions_[sKey], mb_in.rd_ptr() - RTPS::SMHDR_SZ,
    2179           0 :                       RTPS::SMHDR_SZ + octetsToNext, ch, cf, plain_rtps_submessage, ex);
    2180             : 
    2181             :       } else {
    2182           0 :         return CommonUtilities::set_security_error(ex, -2, 2, "Key transform kind unrecognized");
    2183             :       }
    2184             :     }
    2185             :   }
    2186             : 
    2187           0 :   return CommonUtilities::set_security_error(ex, -2, 1, "Crypto Key not found");
    2188           0 : }
    2189             : 
    2190           3 : bool CryptoBuiltInImpl::decode_datawriter_submessage(
    2191             :   DDS::OctetSeq& plain_rtps_submessage,
    2192             :   const DDS::OctetSeq& encoded_rtps_submessage,
    2193             :   DatareaderCryptoHandle receiving_datareader_crypto,
    2194             :   DatawriterCryptoHandle sending_datawriter_crypto,
    2195             :   SecurityException& ex)
    2196             : {
    2197             :   // Allowing Nil Handle for receiver since origin auth is not implemented:
    2198             :   //  if (DDS::HANDLE_NIL == receiving_datareader_crypto) {
    2199             :   //    return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datareader handle");
    2200             :   //  }
    2201           3 :   if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
    2202           3 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datawriter handle");
    2203             :   }
    2204             : 
    2205           0 :   if (security_debug.encdec_debug) {
    2206           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {encdec_debug} CryptoBuiltInImpl::decode_datawriter_submessage ")
    2207             :       ACE_TEXT("Sending DWCH is %u, Receiving DRCH is %u\n"),
    2208             :       sending_datawriter_crypto, receiving_datareader_crypto));
    2209             :   }
    2210             : 
    2211           0 :   return decode_submessage(plain_rtps_submessage, encoded_rtps_submessage,
    2212           0 :                            sending_datawriter_crypto, ex);
    2213             : }
    2214             : 
    2215           1 : bool CryptoBuiltInImpl::decode_datareader_submessage(
    2216             :   DDS::OctetSeq& plain_rtps_submessage,
    2217             :   const DDS::OctetSeq& encoded_rtps_submessage,
    2218             :   DatawriterCryptoHandle receiving_datawriter_crypto,
    2219             :   DatareaderCryptoHandle sending_datareader_crypto,
    2220             :   SecurityException& ex)
    2221             : {
    2222           1 :   if (DDS::HANDLE_NIL == sending_datareader_crypto) {
    2223           1 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datareader handle");
    2224             :   }
    2225             :   // Allowing Nil Handle for receiver since origin auth is not implemented:
    2226             :   //  if (DDS::HANDLE_NIL == receiving_datawriter_crypto) {
    2227             :   //    return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datawriter handle");
    2228             :   //  }
    2229             : 
    2230           0 :   if (security_debug.encdec_debug) {
    2231           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {encdec_debug} CryptoBuiltInImpl::decode_datareader_submessage ")
    2232             :       ACE_TEXT("Sending DRCH is %u, Receiving DWCH is %u\n"),
    2233             :       sending_datareader_crypto, receiving_datawriter_crypto));
    2234             :   }
    2235             : 
    2236           0 :   return decode_submessage(plain_rtps_submessage, encoded_rtps_submessage,
    2237           0 :                            sending_datareader_crypto, ex);
    2238             : }
    2239             : 
    2240           3 : bool CryptoBuiltInImpl::decode_serialized_payload(
    2241             :   DDS::OctetSeq& plain_buffer,
    2242             :   const DDS::OctetSeq& encoded_buffer,
    2243             :   const DDS::OctetSeq& /*inline_qos*/,
    2244             :   DatareaderCryptoHandle receiving_datareader_crypto,
    2245             :   DatawriterCryptoHandle sending_datawriter_crypto,
    2246             :   SecurityException& ex)
    2247             : {
    2248             :   // Not currently requring a reader handle here, origin authentication
    2249             :   // for data payloads is not supported.
    2250             :   // if (DDS::HANDLE_NIL == receiving_datareader_crypto) {
    2251             :   //   return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datareader handle");
    2252             :   // }
    2253           3 :   if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
    2254           2 :     return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datawriter handle");
    2255             :   }
    2256             : 
    2257           1 :   if (security_debug.encdec_debug) {
    2258           0 :     ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {encdec_debug} CryptoBuiltInImpl::decode_serialized_payload ")
    2259             :       ACE_TEXT("Sending DWCH is %u, Receiving DRCH is %u\n"),
    2260             :       sending_datawriter_crypto, receiving_datareader_crypto));
    2261             :   }
    2262             : 
    2263           1 :   ACE_Guard<ACE_Thread_Mutex> guard(mutex_);
    2264           1 :   const KeyTable_t::const_iterator iter = keys_.find(sending_datawriter_crypto);
    2265           1 :   if (iter == keys_.end()) {
    2266           0 :     return CommonUtilities::set_security_error(ex, -1, 1, "No key for DataWriter crypto handle");
    2267             :   }
    2268           1 :   const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(sending_datawriter_crypto);
    2269           1 :   if (eo_iter == encrypt_options_.end()) {
    2270           0 :     return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
    2271             :   }
    2272           1 :   if (!eo_iter->second.payload_) {
    2273           1 :     plain_buffer = encoded_buffer;
    2274           1 :     if (security_debug.encdec_debug) {
    2275           0 :       ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {encdec_debug} CryptoBuiltInImpl::decode_serialized_payload ")
    2276             :         ACE_TEXT("Sending datawriter isn't encrypting as far as we know, returning input as plaintext\n"),
    2277             :         sending_datawriter_crypto, receiving_datareader_crypto));
    2278             :     }
    2279           1 :     return true;
    2280             :   }
    2281             : 
    2282             :   ACE_Message_Block mb_in(to_mb(encoded_buffer.get_buffer()),
    2283           0 :                           encoded_buffer.length());
    2284           0 :   mb_in.wr_ptr(encoded_buffer.length());
    2285           0 :   Serializer de_ser(&mb_in, common_encoding);
    2286           0 :   CryptoHeader ch = CryptoHeader();
    2287           0 :   if (!(de_ser >> ch)) {
    2288           0 :     return CommonUtilities::set_security_error(ex, -3, 4, "Failed to deserialize CryptoHeader");
    2289             :   }
    2290             : 
    2291           0 :   const KeySeq& keyseq = iter->second;
    2292           0 :   for (unsigned int i = 0; i < keyseq.length(); ++i) {
    2293           0 :     if (matches(keyseq[i], ch)) {
    2294           0 :       const KeyId_t sKey = std::make_pair(sending_datawriter_crypto, i);
    2295           0 :       if (encrypts(keyseq[i])) {
    2296             :         ACE_CDR::ULong n;
    2297           0 :         if (!(de_ser >> n)) {
    2298           0 :           return CommonUtilities::set_security_error(ex, -3, 5, "Failed to deserialize CryptoContent length");
    2299             :         }
    2300           0 :         const char* const ciphertext = mb_in.rd_ptr();
    2301           0 :         if (!de_ser.skip(n)) {
    2302           0 :           return CommonUtilities::set_security_error(ex, -3, 7, "Failed to locate CryptoFooter");
    2303             :         }
    2304           0 :         CryptoFooter cf;
    2305           0 :         if (!(de_ser >> cf)) {
    2306           0 :           return CommonUtilities::set_security_error(ex, -3, 6, "Failed to deserialize CryptoFooter");
    2307             :         }
    2308           0 :         return decrypt(keyseq[i], sessions_[sKey], ciphertext, n, ch, cf, plain_buffer, ex);
    2309             : 
    2310           0 :       } else if (authenticates(keyseq[i])) {
    2311           0 :         return CommonUtilities::set_security_error(ex, -3, 3, "Auth-only payload "
    2312             :                                                    "transformation not supported "
    2313           0 :                                                    "(DDSSEC12-59)");
    2314             : 
    2315             :       } else {
    2316           0 :         return CommonUtilities::set_security_error(ex, -3, 2, "Key transform kind unrecognized");
    2317             :       }
    2318             :     }
    2319             :   }
    2320             : 
    2321           0 :   return CommonUtilities::set_security_error(ex, -3, 1, "Crypto Key not found");
    2322           1 : }
    2323             : 
    2324             : }
    2325             : }
    2326             : 
    2327             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16