OpenDDS  Snapshot(2023/04/28-20:55)
CryptoBuiltInImpl.cpp
Go to the documentation of this file.
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"
19 #include "dds/DCPS/Serializer.h"
20 #include "dds/DCPS/Util.h"
21 
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 
35 
36 using namespace DDS::Security;
45 
47 
48 namespace OpenDDS {
49 namespace Security {
50 
51 CryptoBuiltInImpl::CryptoBuiltInImpl()
52  : mutex_()
53  , next_handle_(1)
54 {
55  openssl_init();
56 }
57 
59 {
60  if (DCPS::security_debug.bookkeeping) {
61  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(),
66  sessions_.size(),
67  derived_key_handles_.size()));
68  }
69 
71 }
72 
73 bool CryptoBuiltInImpl::_is_a(const char* id)
74 {
75  return CryptoKeyFactory::_is_a(id)
76  || CryptoKeyExchange::_is_a(id)
77  || CryptoTransform::_is_a(id);
78 }
79 
81 {
82  return "";
83 }
84 
86 {
87  return false;
88 }
89 
91 {
93  return generate_handle_i();
94 }
95 
97 {
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  KeyMaterial_AES_GCM_GMAC make_key(unsigned int key_id, bool encrypt)
110  {
112 
113  for (unsigned int i = 0; i < TransformKindIndex; ++i) {
114  k.transformation_kind[i] = 0;
115  }
119 
120  k.master_salt.length(KEY_LEN_BYTES);
121  RAND_bytes(k.master_salt.get_buffer(), KEY_LEN_BYTES);
122 
123  for (unsigned int i = 0; i < sizeof k.sender_key_id; ++i) {
124  k.sender_key_id[i] = key_id >> (8 * i);
125  }
126 
127  k.master_sender_key.length(KEY_LEN_BYTES);
128  RAND_bytes(k.master_sender_key.get_buffer(), KEY_LEN_BYTES);
129 
130  for (unsigned int i = 0; i < sizeof k.receiver_specific_key_id; ++i) {
131  k.receiver_specific_key_id[i] = 0;
132  }
133 
134  k.master_receiver_specific_key.length(0);
135  return k;
136  }
137 
138  const unsigned submessage_key_index = 0;
139 }
140 
142  IdentityHandle participant_identity,
143  PermissionsHandle participant_permissions,
144  const DDS::PropertySeq&,
145  const ParticipantSecurityAttributes& participant_security_attributes,
146  SecurityException& ex)
147 {
148  if (DDS::HANDLE_NIL == participant_identity) {
149  CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant ID");
150  return DDS::HANDLE_NIL;
151  }
152  if (DDS::HANDLE_NIL == participant_permissions) {
153  CommonUtilities::set_security_error(ex, -1, 0, "Invalid local permissions");
154  return DDS::HANDLE_NIL;
155  }
156 
157  if (!participant_security_attributes.is_rtps_protected) {
158  return DDS::HANDLE_NIL;
159  }
160 
162  const KeyMaterial key = make_key(h,
164  KeySeq keys;
165  DCPS::push_back(keys, key);
166 
168  keys_[h] = keys;
169  if (DCPS::security_debug.bookkeeping) {
170  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  return h;
175 }
176 
179  IdentityHandle remote_participant_identity,
180  PermissionsHandle remote_participant_permissions,
181  SharedSecretHandle* shared_secret,
182  SecurityException& ex)
183 {
184  if (DDS::HANDLE_NIL == remote_participant_identity) {
185  CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant ID");
186  return DDS::HANDLE_NIL;
187  }
188  if (DDS::HANDLE_NIL == remote_participant_permissions) {
189  CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant permissions");
190  return DDS::HANDLE_NIL;
191  }
192  if (!shared_secret) {
193  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret data");
194  return DDS::HANDLE_NIL;
195  }
196 
197  return generate_handle();
198 }
199 
200 namespace {
201 
202  bool operator==(const TAO::String_Manager& lhs, const char* rhs)
203  {
204  return 0 == std::strcmp(lhs, rhs);
205  }
206 
207  bool operator==(const char* lhs, const TAO::String_Manager& rhs)
208  {
209  return 0 == std::strcmp(lhs, rhs);
210  }
211 
212  bool is_builtin_volatile(const DDS::PropertySeq& props)
213  {
214  for (unsigned int i = 0; i < props.length(); ++i) {
215  if (props[i].name == "dds.sec.builtin_endpoint_name") {
216  return props[i].value == "BuiltinParticipantVolatileMessageSecureWriter"
217  || props[i].value == "BuiltinParticipantVolatileMessageSecureReader";
218  }
219  }
220  return false;
221  }
222 
223  const unsigned char VOLATILE_PLACEHOLDER_KIND[] = {DCPS::VENDORID_OCI[0], DCPS::VENDORID_OCI[1], 0, 1};
224 
225  bool is_volatile_placeholder(const KeyMaterial_AES_GCM_GMAC& keymat)
226  {
227  return 0 == std::memcmp(VOLATILE_PLACEHOLDER_KIND, keymat.transformation_kind, sizeof VOLATILE_PLACEHOLDER_KIND);
228  }
229 
230  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
235  std::memcpy(k.transformation_kind, VOLATILE_PLACEHOLDER_KIND, sizeof VOLATILE_PLACEHOLDER_KIND);
236  std::memset(k.sender_key_id, 0, sizeof k.sender_key_id);
237  std::memset(k.receiver_specific_key_id, 0, sizeof k.receiver_specific_key_id);
238  return k;
239  }
240 
241  struct PrivateKey {
243  explicit PrivateKey(const KeyOctetSeq& key)
244  : pkey_(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, 0, key.get_buffer(), key.length()))
245  {}
246  explicit PrivateKey(const DDS::OctetSeq& key)
247  : pkey_(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, 0, key.get_buffer(), key.length()))
248  {}
249  operator EVP_PKEY*() { return pkey_; }
250  ~PrivateKey() { EVP_PKEY_free(pkey_); }
251  };
252 
253  struct DigestContext {
254  EVP_MD_CTX* ctx_;
255  DigestContext() : ctx_(EVP_MD_CTX_new()) {}
256  operator EVP_MD_CTX*() { return ctx_; }
257  ~DigestContext() { EVP_MD_CTX_free(ctx_); }
258  };
259 
260  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  char* const cookie_buffer = const_cast<char*>(cookie); // OctetSeq has no const
265  DDS::OctetSeq cookieSeq(16, 16, reinterpret_cast<CORBA::Octet*>(cookie_buffer));
266  std::vector<const DDS::OctetSeq*> input(3);
267  input[0] = prefix.ptr();
268  input[1] = &cookieSeq;
269  input[2] = suffix.ptr();
271  if (SSL::hash(input, key) != 0) {
272  return;
273  }
274 
275  PrivateKey pkey(key);
276  DigestContext ctx;
277  const EVP_MD* const md = EVP_get_digestbyname("SHA256");
278  if (EVP_DigestInit_ex(ctx, md, 0) != 1) {
279  return;
280  }
281 
282  if (EVP_DigestSignInit(ctx, 0, md, 0, pkey) != 1) {
283  return;
284  }
285 
286  if (EVP_DigestSignUpdate(ctx, data->get_buffer(), data->length()) != 1) {
287  return;
288  }
289 
290  size_t req = 0;
291  if (EVP_DigestSignFinal(ctx, 0, &req) != 1) {
292  return;
293  }
294 
295  result.length(static_cast<unsigned int>(req));
296  if (EVP_DigestSignFinal(ctx, result.get_buffer(), &req) != 1) {
297  result.length(0);
298  }
299  }
300 
301  KeyMaterial_AES_GCM_GMAC
302  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  KeyMaterial_AES_GCM_GMAC k = {
310  KeyOctetSeq(), {0, 0, 0, 0}, KeyOctetSeq(), {0, 0, 0, 0}, KeyOctetSeq()
311  };
312  hkdf(k.master_salt, challenge1, KxSaltCookie, challenge2, sharedSec);
313  hkdf(k.master_sender_key, challenge2, KxKeyCookie, challenge1, sharedSec);
314  return k;
315  }
316 }
317 
319  ParticipantCryptoHandle participant_crypto,
320  const DDS::PropertySeq& properties,
321  const EndpointSecurityAttributes& security_attributes,
323 {
325  const PluginEndpointSecurityAttributesMask plugin_attribs =
326  security_attributes.plugin_endpoint_attributes;
327  KeySeq keys;
328 
329  if (is_builtin_volatile(properties)) {
330  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  bool used_h = false;
336  if (security_attributes.is_submessage_protected) {
337  const KeyMaterial key = make_key(h, plugin_attribs & FLAG_IS_SUBMESSAGE_ENCRYPTED);
338  DCPS::push_back(keys, key);
339  used_h = true;
341  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  if (security_debug.showkeys) {
346  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  }
351  if (security_attributes.is_payload_protected) {
352  const unsigned int key_id = used_h ? generate_handle() : h;
353  const KeyMaterial_AES_GCM_GMAC key = make_key(key_id, plugin_attribs & FLAG_IS_PAYLOAD_ENCRYPTED);
354  DCPS::push_back(keys, key);
356  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  if (security_debug.showkeys) {
361  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  }
366  }
367 
369  keys_[h] = keys;
370  if (DCPS::security_debug.bookkeeping) {
371  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  encrypt_options_[h] = security_attributes;
376  if (DCPS::security_debug.bookkeeping) {
377  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  if (participant_crypto != DDS::HANDLE_NIL) {
383  const EntityInfo e(DATAWRITER_SUBMESSAGE, h);
384  participant_to_entity_.insert(std::make_pair(participant_crypto, e));
385  if (DCPS::security_debug.bookkeeping) {
386  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  return h;
393 }
394 
396  DatawriterCryptoHandle local_datawriter_crypto_handle,
397  ParticipantCryptoHandle remote_participant_crypto,
398  SharedSecretHandle* shared_secret,
399  bool /*relay_only*/,
400  SecurityException& ex)
401 {
402  if (DDS::HANDLE_NIL == local_datawriter_crypto_handle) {
403  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataWriter Crypto Handle");
404  return DDS::HANDLE_NIL;
405  }
406  if (DDS::HANDLE_NIL == remote_participant_crypto) {
407  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Remote Participant Crypto Handle");
408  return DDS::HANDLE_NIL;
409  }
410  if (!shared_secret) {
411  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret Handle");
412  return DDS::HANDLE_NIL;
413  }
414 
416  const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto_handle);
417  if (iter == keys_.end()) {
418  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataWriter Crypto Handle");
419  return DDS::HANDLE_NIL;
420  }
421 
422  const KeySeq& dw_keys = iter->second;
423  const bool use_derived_key = dw_keys.length() == 1 && is_volatile_placeholder(dw_keys[0]);
424 
425  const HandlePair_t input_handles = std::make_pair(remote_participant_crypto, local_datawriter_crypto_handle);
426  const DerivedKeyIndex_t::iterator existing_handle_iter =
427  use_derived_key ? derived_key_handles_.find(input_handles) : derived_key_handles_.end();
428  const DatareaderCryptoHandle h =
429  (existing_handle_iter == derived_key_handles_.end())
430  ? generate_handle_i() : existing_handle_iter->second;
431 
432  if (use_derived_key) {
433  // Create a key from SharedSecret and track it as if Key Exchange happened
434  KeySeq dr_keys(1);
435  dr_keys.length(1);
436  dr_keys[0] = make_volatile_key(shared_secret->challenge1(),
437  shared_secret->challenge2(),
438  shared_secret->sharedSecret());
439  if (!dr_keys[0].master_salt.length()
440  || !dr_keys[0].master_sender_key.length()) {
441  CommonUtilities::set_security_error(ex, -1, 0, "Couldn't create key for "
442  "volatile remote reader");
443  return DDS::HANDLE_NIL;
444  }
446  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  if (security_debug.showkeys) {
451  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  keys_[h] = dr_keys;
457  if (DCPS::security_debug.bookkeeping) {
458  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  if (existing_handle_iter != derived_key_handles_.end()) {
463  sessions_.erase(std::make_pair(h, submessage_key_index));
464  if (DCPS::security_debug.bookkeeping) {
465  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  derived_key_handles_[input_handles] = h;
471  if (DCPS::security_debug.bookkeeping) {
472  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  }
478 
479  const EntityInfo e(DATAREADER_SUBMESSAGE, h);
480  participant_to_entity_.insert(std::make_pair(remote_participant_crypto, e));
481  if (DCPS::security_debug.bookkeeping) {
482  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  encrypt_options_[h] = encrypt_options_[local_datawriter_crypto_handle];
487  if (DCPS::security_debug.bookkeeping) {
488  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  return h;
493 }
494 
496  ParticipantCryptoHandle participant_crypto,
497  const DDS::PropertySeq& properties,
498  const EndpointSecurityAttributes& security_attributes,
500 {
502  const PluginEndpointSecurityAttributesMask plugin_attribs = security_attributes.plugin_endpoint_attributes;
503  KeySeq keys;
504 
505  if (is_builtin_volatile(properties)) {
506  DCPS::push_back(keys, make_volatile_placeholder());
507 
508  } else if (security_attributes.is_submessage_protected) {
509  const KeyMaterial key = make_key(h, plugin_attribs & FLAG_IS_SUBMESSAGE_ENCRYPTED);
511  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  if (security_debug.showkeys) {
516  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  DCPS::push_back(keys, key);
521  }
522 
524  keys_[h] = keys;
525  if (DCPS::security_debug.bookkeeping) {
526  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  encrypt_options_[h] = security_attributes;
531  if (DCPS::security_debug.bookkeeping) {
532  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  if (participant_crypto != DDS::HANDLE_NIL) {
538  const EntityInfo e(DATAREADER_SUBMESSAGE, h);
539  participant_to_entity_.insert(std::make_pair(participant_crypto, e));
540  if (DCPS::security_debug.bookkeeping) {
541  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  return h;
548 }
549 
551  DatareaderCryptoHandle local_datareader_crypto_handle,
552  ParticipantCryptoHandle remote_participant_crypto,
553  SharedSecretHandle* shared_secret,
554  SecurityException& ex)
555 {
556  if (DDS::HANDLE_NIL == local_datareader_crypto_handle) {
557  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataReader Crypto Handle");
558  return DDS::HANDLE_NIL;
559  }
560  if (DDS::HANDLE_NIL == remote_participant_crypto) {
561  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Remote Participant Crypto Handle");
562  return DDS::HANDLE_NIL;
563  }
564  if (!shared_secret) {
565  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Shared Secret Handle");
566  return DDS::HANDLE_NIL;
567  }
568 
570  const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto_handle);
571  if (iter == keys_.end()) {
572  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Local DataReader Crypto Handle");
573  return DDS::HANDLE_NIL;
574  }
575 
576  const KeySeq& dr_keys = iter->second;
577  const bool use_derived_key = dr_keys.length() == 1 && is_volatile_placeholder(dr_keys[0]);
578 
579  const HandlePair_t input_handles = std::make_pair(remote_participant_crypto, local_datareader_crypto_handle);
580  const DerivedKeyIndex_t::iterator existing_handle_iter =
581  use_derived_key ? derived_key_handles_.find(input_handles) : derived_key_handles_.end();
582  const DatareaderCryptoHandle h =
583  (existing_handle_iter == derived_key_handles_.end())
584  ? generate_handle_i() : existing_handle_iter->second;
585 
586  if (use_derived_key) {
587  // Create a key from SharedSecret and track it as if Key Exchange happened
588  KeySeq dw_keys(1);
589  dw_keys.length(1);
590  dw_keys[0] = make_volatile_key(shared_secret->challenge1(),
591  shared_secret->challenge2(),
592  shared_secret->sharedSecret());
593  if (!dw_keys[0].master_salt.length()
594  || !dw_keys[0].master_sender_key.length()) {
595  CommonUtilities::set_security_error(ex, -1, 0, "Couldn't create key for "
596  "volatile remote writer");
597  return DDS::HANDLE_NIL;
598  }
600  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  if (security_debug.showkeys) {
605  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  keys_[h] = dw_keys;
611  if (DCPS::security_debug.bookkeeping) {
612  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  if (existing_handle_iter != derived_key_handles_.end()) {
617  sessions_.erase(std::make_pair(h, submessage_key_index));
618  if (DCPS::security_debug.bookkeeping) {
619  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  derived_key_handles_[input_handles] = h;
625  if (DCPS::security_debug.bookkeeping) {
626  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  }
632 
633  const EntityInfo e(DATAWRITER_SUBMESSAGE, h);
634  participant_to_entity_.insert(std::make_pair(remote_participant_crypto, e));
635  if (DCPS::security_debug.bookkeeping) {
636  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  encrypt_options_[h] = encrypt_options_[local_datareader_crypto_handle];
641  if (DCPS::security_debug.bookkeeping) {
642  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  return h;
647 }
648 
650 {
651  if (DDS::HANDLE_NIL == handle) {
652  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
653  }
654 
656  clear_common_data(handle);
657  for (DerivedKeyIndex_t::iterator it = derived_key_handles_.lower_bound(std::make_pair(handle, 0));
658  it != derived_key_handles_.end() && it->first.first == handle; derived_key_handles_.erase(it++)) {
659  if (DCPS::security_debug.bookkeeping) {
660  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  return true;
666 }
667 
669 {
670  keys_.erase(handle);
671  if (DCPS::security_debug.bookkeeping) {
672  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  for (SessionTable_t::iterator st_iter = sessions_.lower_bound(std::make_pair(handle, 0));
677  st_iter != sessions_.end() && st_iter->first.first == handle;
678  sessions_.erase(st_iter++)) {
679  if (DCPS::security_debug.bookkeeping) {
680  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 }
686 
688 {
689  clear_common_data(handle);
690  encrypt_options_.erase(handle);
691  if (DCPS::security_debug.bookkeeping) {
692  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  for (iter_t it = participant_to_entity_.begin(); it != participant_to_entity_.end();) {
699  if (it->second.handle_ == handle) {
700  participant_to_entity_.erase(it++);
701  if (DCPS::security_debug.bookkeeping) {
702  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  ++it;
708  }
709  }
710 }
711 
713 {
714  if (DDS::HANDLE_NIL == handle) {
715  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
716  }
717 
719  clear_endpoint_data(handle);
720  return true;
721 }
722 
724 {
725  if (DDS::HANDLE_NIL == handle) {
726  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Crypto Handle");
727  }
728 
730  clear_endpoint_data(handle);
731  return true;
732 }
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  const char* to_mb(const unsigned char* buffer)
742  {
743  return reinterpret_cast<const char*>(buffer);
744  }
745 
746  ParticipantCryptoTokenSeq keys_to_tokens(const KeyMaterial_AES_GCM_GMAC_Seq& keys)
747  {
749  for (unsigned int i = 0; i < keys.length(); ++i) {
750  CryptoToken t;
751  t.class_id = Crypto_Token_Class_Id;
752  t.binary_properties.length(1);
754  p.name = Token_KeyMat_Name;
755  p.propagate = true;
756  const size_t size = serialized_size(common_encoding, keys[i]);
757  p.value.length(static_cast<unsigned int>(size));
758  ACE_Message_Block mb(to_mb(p.value.get_buffer()), size);
759  Serializer ser(&mb, common_encoding);
760  if (ser << keys[i]) {
761  DCPS::push_back(tokens, t);
762  } else {
764  "(%P|%t) ERROR: keys_to_tokens: Failed to serialize\n"));
765  }
766  }
767  return tokens;
768  }
769 
770  KeyMaterial_AES_GCM_GMAC_Seq tokens_to_keys(const ParticipantCryptoTokenSeq& tokens)
771  {
773  for (unsigned int i = 0; i < tokens.length(); ++i) {
774  const CryptoToken& t = tokens[i];
775  if (Crypto_Token_Class_Id == t.class_id) {
776  for (unsigned int j = 0; j < t.binary_properties.length(); ++j) {
778  if (Token_KeyMat_Name == p.name) {
779  ACE_Message_Block mb(to_mb(p.value.get_buffer()), p.value.length());
780  mb.wr_ptr(p.value.length());
781  Serializer ser(&mb, common_encoding);
783  if (ser >> key) {
784  DCPS::push_back(keys, key);
785  } else {
787  "(%P|%t) ERROR: tokens_to_keys: Failed to deserialize\n"));
788  }
789  break;
790  }
791  }
792  }
793  }
794  return keys;
795  }
796 }
797 
799  ParticipantCryptoTokenSeq& local_participant_crypto_tokens,
800  ParticipantCryptoHandle local_participant_crypto,
801  ParticipantCryptoHandle remote_participant_crypto,
802  SecurityException& ex)
803 {
804  if (DDS::HANDLE_NIL == local_participant_crypto) {
805  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant handle");
806  }
807  if (DDS::HANDLE_NIL == remote_participant_crypto) {
808  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant handle");
809  }
810 
812  const KeyTable_t::const_iterator iter = keys_.find(local_participant_crypto);
813  if (iter != keys_.end()) {
814  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  local_participant_crypto_tokens.length(0);
818  }
819 
820  return true;
821 }
822 
824  DDS::Security::ParticipantCryptoHandle local_participant_crypto,
825  DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
826 {
827  if (DDS::HANDLE_NIL == local_participant_crypto) {
828  return false;
829  }
830  if (DDS::HANDLE_NIL == remote_participant_crypto) {
831  return false;
832  }
833 
835  const KeyTable_t::const_iterator iter = keys_.find(local_participant_crypto);
836  if (iter == keys_.end()) {
837  return false;
838  }
839  return iter->second.length();
840 }
841 
843  ParticipantCryptoHandle local_participant_crypto,
844  ParticipantCryptoHandle remote_participant_crypto,
845  const ParticipantCryptoTokenSeq& remote_participant_tokens,
846  SecurityException& ex)
847 {
848  if (DDS::HANDLE_NIL == local_participant_crypto) {
849  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local participant handle");
850  }
851  if (DDS::HANDLE_NIL == remote_participant_crypto) {
852  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote participant handle");
853  }
854 
856  keys_[remote_participant_crypto] = tokens_to_keys(remote_participant_tokens);
857  if (DCPS::security_debug.bookkeeping) {
858  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  return true;
863 }
864 
866  DDS::Security::ParticipantCryptoHandle local_participant_crypto,
867  DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
868 {
869  if (DDS::HANDLE_NIL == local_participant_crypto) {
870  return false;
871  }
872  if (DDS::HANDLE_NIL == remote_participant_crypto) {
873  return false;
874  }
875 
877  const KeyTable_t::const_iterator iter = keys_.find(remote_participant_crypto);
878  if (iter == keys_.end()) {
879  return false;
880  }
881  return iter->second.length();
882 }
883 
885  DatawriterCryptoTokenSeq& local_datawriter_crypto_tokens,
886  DatawriterCryptoHandle local_datawriter_crypto,
887  DatareaderCryptoHandle remote_datareader_crypto,
888  SecurityException& ex)
889 {
890  if (DDS::HANDLE_NIL == local_datawriter_crypto) {
891  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local writer handle");
892  }
893  if (DDS::HANDLE_NIL == remote_datareader_crypto) {
894  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote reader handle");
895  }
896 
898  const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto);
899  if (iter != keys_.end()) {
900  local_datawriter_crypto_tokens = keys_to_tokens(iter->second);
901  } else {
902  local_datawriter_crypto_tokens.length(0);
903  }
904 
905  return true;
906 }
907 
909  DatawriterCryptoHandle local_datawriter_crypto,
910  DatareaderCryptoHandle remote_datareader_crypto)
911 {
912  if (DDS::HANDLE_NIL == local_datawriter_crypto) {
913  return false;
914  }
915  if (DDS::HANDLE_NIL == remote_datareader_crypto) {
916  return false;
917  }
918 
920  const KeyTable_t::const_iterator iter = keys_.find(local_datawriter_crypto);
921  if (iter == keys_.end()) {
922  return false;
923  }
924  return iter->second.length();
925 }
926 
928  DatareaderCryptoHandle local_datareader_crypto,
929  DatawriterCryptoHandle remote_datawriter_crypto,
930  const DatawriterCryptoTokenSeq& remote_datawriter_tokens,
931  SecurityException& ex)
932 {
933  if (DDS::HANDLE_NIL == local_datareader_crypto) {
934  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local datareader handle");
935  }
936  if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
937  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote datawriter handle");
938  }
939 
941  keys_[remote_datawriter_crypto] = tokens_to_keys(remote_datawriter_tokens);
942  if (DCPS::security_debug.bookkeeping) {
943  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  return true;
948 }
949 
951  DatareaderCryptoHandle local_datareader_crypto,
952  DatawriterCryptoHandle remote_datawriter_crypto)
953 {
954  if (DDS::HANDLE_NIL == local_datareader_crypto) {
955  return false;
956  }
957  if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
958  return false;
959  }
960 
962  const KeyTable_t::const_iterator iter = keys_.find(remote_datawriter_crypto);
963  if (iter == keys_.end()) {
964  return false;
965  }
966  return iter->second.length();
967 }
968 
970  DatareaderCryptoTokenSeq& local_datareader_crypto_tokens,
971  DatareaderCryptoHandle local_datareader_crypto,
972  DatawriterCryptoHandle remote_datawriter_crypto,
973  SecurityException& ex)
974 {
975  if (DDS::HANDLE_NIL == local_datareader_crypto) {
976  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local reader handle");
977  }
978  if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
979  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote writer handle");
980  }
981 
983  const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto);
984  if (iter != keys_.end()) {
985  local_datareader_crypto_tokens = keys_to_tokens(iter->second);
986  } else {
987  local_datareader_crypto_tokens.length(0);
988  }
989 
990  return true;
991 }
992 
994  DatareaderCryptoHandle local_datareader_crypto,
995  DatawriterCryptoHandle remote_datawriter_crypto)
996 {
997  if (DDS::HANDLE_NIL == local_datareader_crypto) {
998  return false;
999  }
1000  if (DDS::HANDLE_NIL == remote_datawriter_crypto) {
1001  return false;
1002  }
1003 
1005  const KeyTable_t::const_iterator iter = keys_.find(local_datareader_crypto);
1006  if (iter == keys_.end()) {
1007  return false;
1008  }
1009  return iter->second.length();
1010 }
1011 
1013  DatawriterCryptoHandle local_datawriter_crypto,
1014  DatareaderCryptoHandle remote_datareader_crypto,
1015  const DatareaderCryptoTokenSeq& remote_datareader_tokens,
1016  SecurityException& ex)
1017 {
1018  if (DDS::HANDLE_NIL == local_datawriter_crypto) {
1019  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid local datawriter handle");
1020  }
1021  if (DDS::HANDLE_NIL == remote_datareader_crypto) {
1022  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid remote datareader handle");
1023  }
1024 
1026  keys_[remote_datareader_crypto] = tokens_to_keys(remote_datareader_tokens);
1027  if (DCPS::security_debug.bookkeeping) {
1028  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  return true;
1033 }
1034 
1036  DatawriterCryptoHandle local_datawriter_crypto,
1037  DatareaderCryptoHandle remote_datareader_crypto)
1038 {
1039  if (DDS::HANDLE_NIL == local_datawriter_crypto) {
1040  return false;
1041  }
1042  if (DDS::HANDLE_NIL == remote_datareader_crypto) {
1043  return false;
1044  }
1045 
1047  const KeyTable_t::const_iterator iter = keys_.find(remote_datareader_crypto);
1048  if (iter == keys_.end()) {
1049  return false;
1050  }
1051  return iter->second.length();
1052 }
1053 
1055 {
1056  return true;
1057 }
1058 
1059 
1060 // Transform
1061 
1062 namespace {
1063  bool encrypts(const KeyMaterial_AES_GCM_GMAC& k)
1064  {
1065  const CryptoTransformKind& kind = k.transformation_kind;
1066  return kind[0] == 0 && kind[1] == 0 && kind[2] == 0
1069  }
1070 
1071  bool authenticates(const KeyMaterial_AES_GCM_GMAC& k)
1072  {
1073  const CryptoTransformKind& kind = k.transformation_kind;
1074  return kind[0] == 0 && kind[1] == 0 && kind[2] == 0
1077  }
1078 
1079  struct CipherContext {
1080  EVP_CIPHER_CTX* ctx_;
1081  CipherContext() : ctx_(EVP_CIPHER_CTX_new()) {}
1082  operator EVP_CIPHER_CTX*() { return ctx_; }
1083  ~CipherContext() { EVP_CIPHER_CTX_free(ctx_); }
1084  };
1085 
1086  bool inc32(unsigned char* a)
1087  {
1088  for (int i = 0; i < 4; ++i) {
1089  if (a[i] != 0xff) {
1090  ++a[i];
1091  return false;
1092  }
1093  }
1094  std::fill(a, a + 4, 0);
1095  return true;
1096  }
1097 
1098  const size_t CRYPTO_CONTENT_ADDED_LENGTH = 4;
1099  const size_t CRYPTO_HEADER_LENGTH = 20;
1100 }
1101 
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  if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
1110  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid datawriter handle");
1111  }
1112 
1114  const KeyTable_t::const_iterator keys_iter = keys_.find(sending_datawriter_crypto);
1115  const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(sending_datawriter_crypto);
1116  if (eo_iter == encrypt_options_.end()) {
1117  return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
1118  }
1119  if (keys_iter == keys_.end() || !eo_iter->second.payload_) {
1120  encoded_buffer = plain_buffer;
1121  return true;
1122  }
1123 
1124  const KeySeq& keyseq = keys_iter->second;
1125  if (!keyseq.length()) {
1126  encoded_buffer = plain_buffer;
1127  return true;
1128  }
1129 
1130  bool ok;
1132  CryptoFooter footer;
1133  DDS::OctetSeq out;
1134  const DDS::OctetSeq* pOut = &plain_buffer;
1135  // see register_local_datawriter for the assignment of key indexes in the seq
1136  const unsigned int key_idx = keyseq.length() >= 2 ? 1 : 0;
1137  const KeyId_t sKey = std::make_pair(sending_datawriter_crypto, key_idx);
1138 
1139  if (encrypts(keyseq[key_idx])) {
1140  ok = encrypt(keyseq[key_idx], sessions_[sKey], plain_buffer,
1141  header, footer, out, ex);
1142  pOut = &out;
1143 
1144  } else if (authenticates(keyseq[key_idx])) {
1145  ok = authtag(keyseq[key_idx], sessions_[sKey], plain_buffer,
1146  header, footer, ex);
1147 
1148  } else {
1149  return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
1150  }
1151 
1152  if (!ok) {
1153  return false; // either encrypt() or authtag() already set 'ex'
1154  }
1155 
1156  size_t size = serialized_size(common_encoding, header);
1157 
1158  if (pOut != &plain_buffer) {
1159  size += CRYPTO_CONTENT_ADDED_LENGTH;
1160  }
1161 
1162  size += pOut->length();
1163  serialized_size(common_encoding, size, footer);
1164 
1165  encoded_buffer.length(static_cast<unsigned int>(size));
1166  ACE_Message_Block mb(to_mb(encoded_buffer.get_buffer()), size);
1167  Serializer ser(&mb, common_encoding);
1168  ser << header;
1169 
1170  if (pOut != &plain_buffer) {
1171  ser << pOut->length();
1172  }
1173  ser.write_octet_array(pOut->get_buffer(), pOut->length());
1174 
1175  ser << footer;
1176  return ser.good_bit();
1177 }
1178 
1180 {
1181  RAND_bytes(id_, sizeof id_);
1182  RAND_bytes(iv_suffix_, sizeof iv_suffix_);
1183  derive_key(master);
1184  counter_ = 0;
1185 }
1186 
1188 {
1189  inc32(id_);
1190  RAND_bytes(iv_suffix_, sizeof iv_suffix_);
1191  key_.length(0);
1192  derive_key(master);
1193  counter_ = 0;
1194 }
1195 
1197 {
1198  if (inc32(iv_suffix_)) {
1199  inc32(iv_suffix_ + 4);
1200  }
1201 }
1202 
1204  const DDS::OctetSeq& plain,
1206 {
1207  const unsigned int blocks =
1208  (plain.length() + BLOCK_LEN_BYTES - 1) / BLOCK_LEN_BYTES;
1209 
1210  if (!sess.key_.length()) {
1211  sess.create_key(master);
1212 
1213  } else if (sess.counter_ + blocks > MAX_BLOCKS_PER_SESSION) {
1214  sess.next_id(master);
1215 
1216  } else {
1217  sess.inc_iv();
1218  sess.counter_ += blocks;
1219  }
1220 
1221  std::memcpy(&header.transform_identifier.transformation_kind,
1222  &master.transformation_kind, sizeof master.transformation_kind);
1223  std::memcpy(&header.transform_identifier.transformation_key_id,
1224  &master.sender_key_id, sizeof master.sender_key_id);
1225  std::memcpy(&header.session_id, &sess.id_, sizeof sess.id_);
1226  std::memcpy(&header.initialization_vector_suffix, &sess.iv_suffix_, sizeof sess.iv_suffix_);
1227 }
1228 
1230  const DDS::OctetSeq& plain,
1231  CryptoHeader& header, CryptoFooter& footer,
1232  DDS::OctetSeq& out, SecurityException& ex)
1233 {
1234  if (security_debug.showkeys) {
1235  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  encauth_setup(master, sess, plain, header);
1241  static const int IV_LEN = 12, IV_SUFFIX_IDX = 4;
1242  unsigned char iv[IV_LEN];
1243  std::memcpy(iv, &sess.id_, sizeof sess.id_);
1244  std::memcpy(iv + IV_SUFFIX_IDX, &sess.iv_suffix_, sizeof sess.iv_suffix_);
1245 
1247  out = plain;
1248  return true;
1249  }
1250 
1251  CipherContext ctx;
1252  const unsigned char* const key = sess.key_.get_buffer();
1253  if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), 0, key, iv) != 1) {
1254  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptInit_ex");
1255  }
1256 
1257  int len;
1258  out.length(plain.length() + BLOCK_LEN_BYTES - 1);
1259  unsigned char* const out_buffer = out.get_buffer();
1260  if (EVP_EncryptUpdate(ctx, out_buffer, &len,
1261  plain.get_buffer(), plain.length()) != 1) {
1262  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptUpdate");
1263  }
1264 
1265  int padLen;
1266  if (EVP_EncryptFinal_ex(ctx, out_buffer + len, &padLen) != 1) {
1267  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptFinal_ex");
1268  }
1269 
1270  out.length(len + padLen);
1271 
1272  if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, sizeof footer.common_mac,
1273  &footer.common_mac) != 1) {
1274  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
1275  }
1276 
1277  return true;
1278 }
1279 
1281  const DDS::OctetSeq& plain,
1283  CryptoFooter& footer,
1284  SecurityException& ex)
1285 {
1286  encauth_setup(master, sess, plain, header);
1287  static const int IV_LEN = 12, IV_SUFFIX_IDX = 4;
1288  unsigned char iv[IV_LEN];
1289  std::memcpy(iv, &sess.id_, sizeof sess.id_);
1290  std::memcpy(iv + IV_SUFFIX_IDX, &sess.iv_suffix_, sizeof sess.iv_suffix_);
1291 
1292  CipherContext ctx;
1293  const unsigned char* const key = sess.key_.get_buffer();
1294  if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), 0, key, iv) != 1) {
1295  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptInit_ex");
1296  }
1297 
1298  int n;
1299  if (EVP_EncryptUpdate(ctx, 0, &n, plain.get_buffer(), plain.length()) != 1) {
1300  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptUpdate");
1301  }
1302 
1303  if (EVP_EncryptFinal_ex(ctx, 0, &n) != 1) {
1304  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_EncryptFinal_ex");
1305  }
1306 
1307  if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, sizeof footer.common_mac,
1308  &footer.common_mac) != 1) {
1309  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
1310  }
1311 
1312  return true;
1313 }
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  unsigned int findLastSubmessage(const DDS::OctetSeq& plaintext)
1319  {
1320  RTPS::MessageParser parser(plaintext);
1321  const char* const start = parser.current();
1322 
1323  while (parser.remaining() >= RTPS::SMHDR_SZ) {
1324  const unsigned int sm_start = static_cast<unsigned int>(parser.current() - start);
1325 
1326  if (!parser.parseSubmessageHeader()) {
1327  return 0;
1328  }
1329 
1330  if (!parser.hasNextSubmessage()) {
1331  return sm_start;
1332  }
1333 
1334  parser.skipToNextSubmessage();
1335  }
1336 
1337  return 0;
1338  }
1339 
1340  unsigned int roundUp(unsigned int length, unsigned int alignment)
1341  {
1342  const unsigned int offset = length % alignment;
1343  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  bool setOctetsToNextHeader(DDS::OctetSeq& modified, const DDS::OctetSeq& original, unsigned int offset = 0)
1353  {
1354  if (offset + RTPS::SMHDR_SZ >= original.length()) {
1355  return false;
1356  }
1357 
1358  const size_t origLength = original.length() - offset;
1359  ACE_Message_Block mb_in(to_mb(original.get_buffer() + offset), origLength);
1360  mb_in.wr_ptr(origLength);
1361 
1362  Serializer ser_in(&mb_in, common_encoding);
1363  ser_in.skip(1); // submessageId
1364 
1365  unsigned char flags;
1366  ser_in >> ACE_InputCDR::to_octet(flags);
1367  const int flag_e = flags & RTPS::FLAG_E;
1368  ser_in.swap_bytes(ACE_CDR_BYTE_ORDER != flag_e);
1369 
1370  ACE_UINT16 submessageLength;
1371  ser_in >> submessageLength;
1372  if (submessageLength == 0) {
1373  modified = original;
1374  const size_t len = roundUp(static_cast<unsigned int>(origLength - RTPS::SMHDR_SZ), RTPS::SM_ALIGN);
1375  modified[offset + 2 + !flag_e] = len & 0xff;
1376  modified[offset + 2 + flag_e] = (len >> 8) & 0xff;
1377  return true;
1378  }
1379  return false;
1380  }
1381 }
1382 
1384  DDS::OctetSeq& encoded_rtps_submessage,
1385  const DDS::OctetSeq& plain_rtps_submessage,
1386  NativeCryptoHandle sender_handle,
1387  SecurityException& ex)
1388 {
1389  const KeyTable_t::const_iterator iter = keys_.find(sender_handle);
1390  if (iter == keys_.end()) {
1391  encoded_rtps_submessage = plain_rtps_submessage;
1392  return true;
1393  }
1394 
1395  const KeySeq& keyseq = iter->second;
1396  if (!keyseq.length()) {
1397  encoded_rtps_submessage = plain_rtps_submessage;
1398  return true;
1399  }
1400 
1401  bool ok;
1403  CryptoFooter footer;
1404  DDS::OctetSeq out;
1405  const DDS::OctetSeq* pOut = &plain_rtps_submessage;
1406  const KeyId_t sKey = std::make_pair(sender_handle, submessage_key_index);
1407  bool authOnly = false;
1408 
1409  if (encrypts(keyseq[submessage_key_index])) {
1410  ok = encrypt(keyseq[submessage_key_index], sessions_[sKey], plain_rtps_submessage,
1411  header, footer, out, ex);
1412  pOut = &out;
1413 
1414  } 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  if (setOctetsToNextHeader(out, plain_rtps_submessage)) {
1418  pOut = &out;
1419  }
1420  ok = authtag(keyseq[submessage_key_index], sessions_[sKey], *pOut,
1421  header, footer, ex);
1422  authOnly = true;
1423 
1424  } else {
1425  return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
1426  }
1427 
1428  if (!ok) {
1429  return false; // either encrypt() or authtag() already set 'ex'
1430  }
1431 
1432  size_t size = 0;
1433 
1434  size += RTPS::SMHDR_SZ; // prefix submessage header
1435  serialized_size(common_encoding, size, header);
1436  const ACE_UINT16 hdrLen = static_cast<ACE_UINT16>(size - RTPS::SMHDR_SZ);
1437 
1438  if (!authOnly) {
1439  size += RTPS::SMHDR_SZ + SEQLEN_SZ;
1440  }
1441 
1442  size += pOut->length(); // submessage inside wrapper
1443  align(size, RTPS::SM_ALIGN);
1444 
1445  size += RTPS::SMHDR_SZ; // postfix submessage header
1446  const size_t preFooter = size;
1447  serialized_size(common_encoding, size, footer);
1448 
1449  encoded_rtps_submessage.length(static_cast<unsigned int>(size));
1450  ACE_Message_Block mb(to_mb(encoded_rtps_submessage.get_buffer()), size);
1451  Serializer ser(&mb, common_encoding);
1452  RTPS::SubmessageHeader smHdr = {RTPS::SEC_PREFIX, 0, hdrLen};
1453  ser << smHdr;
1454  ser << header;
1455 
1456  if (!authOnly) {
1457  smHdr.submessageId = RTPS::SEC_BODY;
1458  smHdr.submessageLength = static_cast<ACE_UINT16>(roundUp(SEQLEN_SZ + pOut->length(), RTPS::SM_ALIGN));
1459  ser << smHdr;
1460  ser << pOut->length();
1461  }
1462 
1463  ser.write_octet_array(pOut->get_buffer(), pOut->length());
1464  ser.align_w(RTPS::SM_ALIGN);
1465 
1466  smHdr.submessageId = RTPS::SEC_POSTFIX;
1467  smHdr.submessageLength = static_cast<ACE_UINT16>(size - preFooter);
1468  ser << smHdr;
1469  ser << footer;
1470 
1471  return ser.good_bit();
1472 }
1473 
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  if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
1483  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataWriter handle");
1484  }
1485 
1486  if (receiving_datareader_crypto_list_index < 0) {
1487  return CommonUtilities::set_security_error(ex, -1, 0, "Negative list index");
1488  }
1489 
1490  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  if (len && receiving_datareader_crypto_list_index >= len) {
1494  return CommonUtilities::set_security_error(ex, -1, 0, "List index too large");
1495  }
1496 
1497  for (unsigned int i = 0; i < receiving_datareader_crypto_list.length(); ++i) {
1498  if (receiving_datareader_crypto_list[i] == DDS::HANDLE_NIL) {
1499  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataReader handle in list");
1500  }
1501  }
1502 
1503  NativeCryptoHandle encode_handle = sending_datawriter_crypto;
1505  const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(encode_handle);
1506  if (eo_iter == encrypt_options_.end()) {
1507  return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
1508  }
1509 
1510  if (!eo_iter->second.submessage_) {
1511  encoded_rtps_submessage = plain_rtps_submessage;
1512  receiving_datareader_crypto_list_index = len;
1513  return true;
1514  }
1515 
1516  if (receiving_datareader_crypto_list.length() == 1) {
1517  const KeyTable_t::const_iterator iter = keys_.find(encode_handle);
1518  if (iter != keys_.end()) {
1519  const KeySeq& dw_keys = iter->second;
1520  if (dw_keys.length() == 1 && is_volatile_placeholder(dw_keys[0])) {
1521  encode_handle = receiving_datareader_crypto_list[0];
1522  }
1523  }
1524  }
1525 
1526  const bool ok = encode_submessage(encoded_rtps_submessage,
1527  plain_rtps_submessage, encode_handle, ex);
1528  if (ok) {
1529  receiving_datareader_crypto_list_index = len;
1530  }
1531  return ok;
1532 }
1533 
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  if (DDS::HANDLE_NIL == sending_datareader_crypto) {
1542  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataReader handle");
1543  }
1544 
1545  for (unsigned int i = 0; i < receiving_datawriter_crypto_list.length(); ++i) {
1546  if (receiving_datawriter_crypto_list[i] == DDS::HANDLE_NIL) {
1547  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid DataWriter handle in list");
1548  }
1549  }
1550 
1551  NativeCryptoHandle encode_handle = sending_datareader_crypto;
1553  if (receiving_datawriter_crypto_list.length() == 1) {
1554  const KeyTable_t::const_iterator iter = keys_.find(encode_handle);
1555  if (iter != keys_.end()) {
1556  const KeySeq& dr_keys = iter->second;
1557  if (dr_keys.length() == 1 && is_volatile_placeholder(dr_keys[0])) {
1558  encode_handle = receiving_datawriter_crypto_list[0];
1559  }
1560  }
1561  }
1562 
1563  return encode_submessage(encoded_rtps_submessage, plain_rtps_submessage,
1564  encode_handle, ex);
1565 }
1566 
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  receiving_participant_crypto_list_index = receiving_participant_crypto_list.length();
1576  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  return false;
1581  }
1582 
1584  const KeyTable_t::const_iterator iter = keys_.find(sending_participant_crypto);
1585  if (iter == keys_.end()) {
1586  return CommonUtilities::set_security_error(ex, -1, 0, "No entry for sending_participant_crypto");
1587  }
1588 
1589  const KeySeq& keyseq = iter->second;
1590  if (!keyseq.length()) {
1591  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  DDS::OctetSeq transformed(plain_rtps_message.length() + RTPS::SMHDR_SZ);
1596  transformed.length(transformed.maximum());
1597  transformed[0] = RTPS::INFO_SRC;
1598  transformed[1] = 0; // flags: big-endian
1599  transformed[2] = 0; // high byte of octetsToNextHeader
1600  transformed[3] = RTPS::INFO_SRC_SZ;
1601  std::memcpy(transformed.get_buffer() + RTPS::SMHDR_SZ, plain_rtps_message.get_buffer(), plain_rtps_message.length());
1602 
1603  bool ok, addSecBody = false;
1604  CryptoHeader cryptoHdr;
1605  CryptoFooter cryptoFooter;
1606  DDS::OctetSeq out;
1607  const DDS::OctetSeq* pOut = &transformed;
1608  const KeyMaterial& key = keyseq[0];
1609  const KeyId_t sKey = std::make_pair(sending_participant_crypto, 0);
1610 
1611  if (encrypts(key)) {
1612  ok = encrypt(key, sessions_[sKey], transformed, cryptoHdr, cryptoFooter, out, ex);
1613  pOut = &out;
1614  addSecBody = true;
1615 
1616  } 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  const unsigned int offsetFinal = findLastSubmessage(transformed);
1620  if (offsetFinal && setOctetsToNextHeader(out, transformed, offsetFinal)) {
1621  pOut = &out;
1622  }
1623  ok = authtag(key, sessions_[sKey], *pOut, cryptoHdr, cryptoFooter, ex);
1624 
1625  } else {
1626  return CommonUtilities::set_security_error(ex, -1, 0, "Key transform kind unrecognized");
1627  }
1628 
1629  if (!ok) {
1630  return false; // either encrypt() or authtag() already set 'ex'
1631  }
1632 
1633  size_t size = RTPS::RTPSHDR_SZ + RTPS::SMHDR_SZ; // RTPS Header, SRTPS Prefix
1634  serialized_size(common_encoding, size, cryptoHdr);
1635  const ACE_UINT16 cryptoHdrLen =
1636  static_cast<ACE_UINT16>(size - RTPS::RTPSHDR_SZ - RTPS::SMHDR_SZ);
1637 
1638  if (addSecBody) {
1639  size += RTPS::SMHDR_SZ + SEQLEN_SZ;
1640  }
1641 
1642  size += pOut->length();
1643  align(size, RTPS::SM_ALIGN);
1644 
1645  size += RTPS::SMHDR_SZ; // SRTPS Postfix
1646  serialized_size(common_encoding, size, cryptoFooter);
1647 
1648  encoded_rtps_message.length(static_cast<unsigned int>(size));
1649  ACE_Message_Block mb(to_mb(encoded_rtps_message.get_buffer()), size);
1650  Serializer ser(&mb, common_encoding);
1651 
1652  ser.write_octet_array(plain_rtps_message.get_buffer(), RTPS::RTPSHDR_SZ);
1653 
1654  RTPS::SubmessageHeader smHdr = {RTPS::SRTPS_PREFIX, 0, cryptoHdrLen};
1655  ser << smHdr;
1656  ser << cryptoHdr;
1657 
1658  if (addSecBody) {
1659  smHdr.submessageId = RTPS::SEC_BODY;
1660  smHdr.submessageLength = static_cast<ACE_UINT16>(roundUp(SEQLEN_SZ + pOut->length(), RTPS::SM_ALIGN));
1661  ser << smHdr;
1662  ser << pOut->length();
1663  }
1664 
1665  ser.write_octet_array(pOut->get_buffer(), pOut->length());
1666  ser.align_w(RTPS::SM_ALIGN);
1667 
1668  smHdr.submessageId = RTPS::SRTPS_POSTFIX;
1669  smHdr.submessageLength = 0; // final submessage doesn't need a length
1670  ser << smHdr;
1671  ser << cryptoFooter;
1672 
1673  return ser.good_bit();
1674 }
1675 
1676 namespace {
1677  bool matches(const KeyMaterial_AES_GCM_GMAC& k, const CryptoHeader& h)
1678  {
1679  return 0 == std::memcmp(k.transformation_kind,
1681  sizeof(CryptoTransformKind))
1682  && 0 == std::memcmp(k.sender_key_id,
1684  sizeof(CryptoTransformKeyId));
1685  }
1686 }
1687 
1689  DatawriterCryptoHandle& datawriter_crypto,
1690  DatareaderCryptoHandle& datareader_crypto,
1691  SecureSubmessageCategory_t& secure_submessage_category,
1692  const DDS::OctetSeq& encoded_rtps_submessage,
1694  ParticipantCryptoHandle sending_participant_crypto,
1695  SecurityException& ex)
1696 {
1697  if (DDS::HANDLE_NIL == sending_participant_crypto) {
1698  CommonUtilities::set_security_error(ex, -1, 0, "Invalid Sending Participant");
1699  return false;
1700  }
1701 
1702  ACE_Message_Block mb_in(to_mb(encoded_rtps_submessage.get_buffer()),
1703  encoded_rtps_submessage.length());
1704  mb_in.wr_ptr(encoded_rtps_submessage.length());
1705  Serializer de_ser(&mb_in, common_encoding);
1706  CryptoHeader ch = CryptoHeader();
1707  if (!(de_ser.skip(RTPS::SMHDR_SZ) && (de_ser >> ch))) {
1709  "(%P|%t) CryptoBuiltInImpl::preprocess_secure_submsg: "
1710  "Could not deserializer CyptoHeader\n"));
1711  }
1712 
1714  typedef std::multimap<ParticipantCryptoHandle, EntityInfo>::iterator iter_t;
1715  const std::pair<iter_t, iter_t> iters =
1716  participant_to_entity_.equal_range(sending_participant_crypto);
1717  if (security_debug.chlookup) {
1718  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  for (iter_t iter = iters.first; iter != iters.second; ++iter) {
1723  const NativeCryptoHandle sending_entity_candidate = iter->second.handle_;
1724  const KeyTable_t::const_iterator kiter = keys_.find(sending_entity_candidate);
1725  if (security_debug.chlookup) {
1726  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  if (kiter != keys_.end()) {
1731  const KeySeq& keyseq = kiter->second;
1732  const unsigned keycount = keyseq.length();
1733  if (security_debug.chlookup) {
1734  ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
1735  ACE_TEXT(" Number of keys: %u\n"), keycount));
1736  }
1737  for (unsigned int i = 0; i < keycount; ++i) {
1738  if (security_debug.chlookup) {
1739  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  if (matches(keyseq[i], ch)) {
1745  char chtype = '\0';
1746  secure_submessage_category = iter->second.category_;
1747  switch (secure_submessage_category) {
1748  case DATAWRITER_SUBMESSAGE:
1749  datawriter_crypto = iter->second.handle_;
1750  chtype = 'W';
1751  break;
1752  case DATAREADER_SUBMESSAGE:
1753  datareader_crypto = iter->second.handle_;
1754  chtype = 'R';
1755  break;
1756  default:
1757  break;
1758  }
1759  if (security_debug.chlookup && chtype) {
1760  ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {chlookup} CryptoBuiltInImpl::preprocess_secure_submsg: ")
1761  ACE_TEXT("D%cCH Found!\n"), chtype));
1762  }
1763  return true;
1764  }
1765  }
1766  }
1767  }
1768  CommonUtilities::set_security_error(ex, -2, 1, "Crypto Key not registered",
1771  return false;
1772 }
1773 
1776  const CryptoHeader& header)
1777 {
1778  if (key_.length() && 0 == std::memcmp(&id_, &header.session_id, sizeof id_)) {
1779  return key_;
1780  }
1781  std::memcpy(&id_, &header.session_id, sizeof id_);
1782  key_.length(0);
1783  derive_key(master);
1784  return key_;
1785 }
1786 
1788 {
1789  PrivateKey pkey(master.master_sender_key);
1790  DigestContext ctx;
1791  const EVP_MD* md = EVP_get_digestbyname("SHA256");
1792 
1793  if (EVP_DigestInit_ex(ctx, md, 0) < 1) {
1794  return;
1795  }
1796 
1797  if (EVP_DigestSignInit(ctx, 0, md, 0, pkey) < 1) {
1798  return;
1799  }
1800 
1801  static const char cookie[] = "SessionKey"; // DDSSEC12-53: NUL excluded
1802  if (EVP_DigestSignUpdate(ctx, cookie, (sizeof cookie) - 1) < 1) {
1803  return;
1804  }
1805 
1806  const KeyOctetSeq& salt = master.master_salt;
1807  if (EVP_DigestSignUpdate(ctx, salt.get_buffer(), salt.length()) < 1) {
1808  return;
1809  }
1810 
1811  if (EVP_DigestSignUpdate(ctx, id_, sizeof id_) < 1) {
1812  return;
1813  }
1814 
1815  size_t req = 0;
1816  if (EVP_DigestSignFinal(ctx, 0, &req) < 1) {
1817  return;
1818  }
1819 
1820  key_.length(static_cast<unsigned int>(req));
1821  if (EVP_DigestSignFinal(ctx, key_.get_buffer(), &req) < 1) {
1822  key_.length(0);
1823  }
1824 }
1825 
1827  const char* ciphertext, unsigned int n,
1828  const CryptoHeader& header,
1829  const CryptoFooter& footer, DDS::OctetSeq& out,
1830  SecurityException& ex)
1831 
1832 {
1833  if (security_debug.showkeys) {
1834  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  const KeyOctetSeq sess_key = sess.get_key(master, header);
1840  if (!sess_key.length()) {
1841  return CommonUtilities::set_security_error(ex, -1, 0, "no session key");
1842  }
1843 
1846  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
1847  "unsupported transformation kind %d\n",
1849  return CommonUtilities::set_security_error(ex, -1, 0, "unsupported transformation kind");
1850  }
1851 
1853  out.length(n);
1854  std::memcpy(out.get_buffer(), ciphertext, n);
1855  return true;
1856  }
1857 
1858  CipherContext ctx;
1859  // session_id is start of IV contiguous bytes
1860  if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), 0, sess_key.get_buffer(),
1861  header.session_id) != 1) {
1862  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
1863  "EVP_DecryptInit_ex %Ld\n", ERR_peek_last_error()));
1864  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptInit_ex");
1865  }
1866 
1867  out.length(n + KEY_LEN_BYTES);
1868  unsigned char* const out_buffer = out.get_buffer();
1869  int len;
1870  if (EVP_DecryptUpdate(ctx, out_buffer, &len,
1871  reinterpret_cast<const unsigned char*>(ciphertext), n)
1872  != 1) {
1873  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
1874  "EVP_DecryptUpdate %Ld\n", ERR_peek_last_error()));
1875  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptUpdate");
1876  }
1877 
1878  void* tag = const_cast<void*>(static_cast<const void*>(footer.common_mac));
1879  if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
1880  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
1881  "EVP_CIPHER_CTX_ctrl %Ld\n", ERR_peek_last_error()));
1882  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
1883  }
1884 
1885  int len2;
1886  if (EVP_DecryptFinal_ex(ctx, out_buffer + len, &len2) == 1) {
1887  out.length(len + len2);
1888  return true;
1889  }
1890  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::decrypt - ERROR "
1891  "EVP_DecryptFinal_ex %Ld\n", ERR_peek_last_error()));
1892  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptFinal_ex");
1893 }
1894 
1896  const char* in, unsigned int n,
1897  const CryptoHeader& header,
1898  const CryptoFooter& footer, DDS::OctetSeq& out,
1899  SecurityException& ex)
1900 
1901 {
1902  const KeyOctetSeq sess_key = sess.get_key(master, header);
1903  if (!sess_key.length()) {
1904  return CommonUtilities::set_security_error(ex, -1, 0, "no session key");
1905  }
1906 
1909  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
1910  "unsupported transformation kind %d\n",
1912  return CommonUtilities::set_security_error(ex, -1, 0, "unsupported transformation kind");
1913  }
1914 
1915  CipherContext ctx;
1916  // session_id is start of IV contiguous bytes
1917  if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), 0, sess_key.get_buffer(),
1918  header.session_id) != 1) {
1919  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
1920  "EVP_DecryptInit_ex %Ld\n", ERR_peek_last_error()));
1921  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptInit_ex");
1922  }
1923 
1924  int len;
1925  if (EVP_DecryptUpdate(ctx, 0, &len,
1926  reinterpret_cast<const unsigned char*>(in), n) != 1) {
1927  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
1928  "EVP_DecryptUpdate %Ld\n", ERR_peek_last_error()));
1929  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptUpdate");
1930  }
1931 
1932  void* tag = const_cast<void*>(static_cast<const void*>(footer.common_mac));
1933  if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
1934  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
1935  "EVP_CIPHER_CTX_ctrl %Ld\n", ERR_peek_last_error()));
1936  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_CIPHER_CTX_ctrl");
1937  }
1938 
1939  int len2;
1940  if (EVP_DecryptFinal_ex(ctx, 0, &len2) == 1) {
1941  out.length(n);
1942  std::memcpy(out.get_buffer(), in, n);
1943  return true;
1944  }
1945  ACE_ERROR((LM_ERROR, "(%P|%t) CryptoBuiltInImpl::verify - ERROR "
1946  "EVP_DecryptFinal_ex %Ld\n", ERR_peek_last_error()));
1947  return CommonUtilities::set_security_error(ex, -1, 0, "EVP_DecryptFinal_ex");
1948 }
1949 
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  if (DDS::HANDLE_NIL == receiving_participant_crypto) {
1958  return CommonUtilities::set_security_error(ex, -1, 0, "No Receiving Participant handle");
1959  }
1960  if (DDS::HANDLE_NIL == sending_participant_crypto) {
1961  return CommonUtilities::set_security_error(ex, -1, 1, "No Sending Participant handle");
1962  }
1963 
1964  RTPS::MessageParser parser(encoded_buffer);
1965 
1966  if (!parser.parseHeader()) {
1967  return CommonUtilities::set_security_error(ex, -2, 0, "Failed to deserialize Header");
1968  }
1969 
1970  CryptoHeader ch = CryptoHeader();
1971  CryptoFooter cf;
1972  bool haveCryptoHeader = false, haveCryptoFooter = false;
1973  const char* afterSrtpsPrefix = 0;
1974  unsigned int sizeOfAuthenticated, sizeOfEncrypted;
1975  const char* encrypted = 0;
1976 
1977  for (int i = 0; parser.remaining(); ++i) {
1978  if (parser.remaining() < RTPS::SMHDR_SZ || !parser.parseSubmessageHeader()) {
1979  return CommonUtilities::set_security_error(ex, -3, i, "Failed to deserialize SubmessageHeader");
1980  }
1981 
1982  parser.serializer().endianness(ENDIAN_BIG);
1983  const int type = parser.submessageHeader().submessageId;
1984 
1985  if (i == 0 && type == RTPS::SRTPS_PREFIX) {
1986  if (!(parser >> ch)) {
1987  return CommonUtilities::set_security_error(ex, -4, i, "Failed to deserialize CryptoHeader");
1988  }
1989  haveCryptoHeader = true;
1990  if (!parser.skipToNextSubmessage()) {
1991  return CommonUtilities::set_security_error(ex, -5, i, "Failed to find submessage after SRTPS_PREFIX");
1992  }
1993  afterSrtpsPrefix = parser.current();
1994 
1995  } else if (haveCryptoHeader && type == RTPS::SEC_BODY) {
1996  if (!(parser >> sizeOfEncrypted)) {
1997  return CommonUtilities::set_security_error(ex, -13, i, "Failed to deserialize CryptoContent length");
1998  }
1999  const unsigned short sz =
2000  static_cast<unsigned short>(DCPS::uint32_cdr_size);
2001  if (sizeOfEncrypted + sz > parser.submessageHeader().submessageLength) {
2002  return CommonUtilities::set_security_error(ex, -14, i, "CryptoContent length out of bounds");
2003  }
2004  encrypted = parser.current();
2005  if (!parser.skipToNextSubmessage()) {
2006  return CommonUtilities::set_security_error(ex, -15, i, "Failed to find submessage after SEC_BODY");
2007  }
2008 
2009  } else if (haveCryptoHeader && type == RTPS::SRTPS_POSTFIX) {
2010  sizeOfAuthenticated = static_cast<unsigned int>(parser.current() - afterSrtpsPrefix - RTPS::SMHDR_SZ);
2011  if (!(parser >> cf)) {
2012  return CommonUtilities::set_security_error(ex, -7, i, "Failed to deserialize CryptoFooter");
2013  }
2014  if (parser.hasNextSubmessage()) {
2015  return CommonUtilities::set_security_error(ex, -8, i, "SRTPS_POSTFIX was not the final submessage");
2016  }
2017  haveCryptoFooter = true;
2018  break;
2019 
2020  } else {
2021  if (parser.hasNextSubmessage()) {
2022  if (!parser.skipToNextSubmessage()) {
2023  return CommonUtilities::set_security_error(ex, -6, i, "Failed to find next submessage");
2024  }
2025  } else {
2026  break;
2027  }
2028  }
2029  }
2030 
2031  if (!haveCryptoHeader || !haveCryptoFooter) {
2032  return CommonUtilities::set_security_error(ex, -9, 0, "Failed to find SRTPS_PREFIX/POSTFIX wrapper");
2033  }
2034 
2036  const KeyTable_t::const_iterator iter = keys_.find(sending_participant_crypto);
2037  if (iter == keys_.end()) {
2038  return CommonUtilities::set_security_error(ex, -1, 2, "No key for Sending Participant handle");
2039  }
2040  const KeySeq& keyseq = iter->second;
2041  bool foundKey = false;
2042  DDS::OctetSeq transformed;
2043  for (unsigned int i = 0; !foundKey && i < keyseq.length(); ++i) {
2044  if (matches(keyseq[i], ch)) {
2045  const KeyId_t sKey = std::make_pair(sending_participant_crypto, i);
2046 
2047  if (encrypts(keyseq[i])) {
2048  if (!encrypted) {
2049  return CommonUtilities::set_security_error(ex, -15, 0, "Failed to find SEC_BODY submessage");
2050  }
2051  foundKey = true;
2052  if (!decrypt(keyseq[i], sessions_[sKey], encrypted, sizeOfEncrypted,
2053  ch, cf, transformed, ex)) {
2054  return false;
2055  }
2056 
2057  } else if (authenticates(keyseq[i])) {
2058  foundKey = true;
2059  if (!verify(keyseq[i], sessions_[sKey], afterSrtpsPrefix, sizeOfAuthenticated,
2060  ch, cf, transformed, ex)) {
2061  return false;
2062  }
2063 
2064  } else {
2065  return CommonUtilities::set_security_error(ex, -10, 2, "Key transform kind unrecognized");
2066  }
2067  }
2068  }
2069 
2070  if (!foundKey) {
2072  OPENDDS_EXCEPTION_MINOR_CODE_NO_KEY, "Crypto Key not found");
2073  }
2074 
2075  if (transformed.length() < RTPS::SMHDR_SZ + RTPS::INFO_SRC_SZ
2076  || transformed[0] != RTPS::INFO_SRC) {
2077  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  if (std::memcmp(transformed.get_buffer() + RTPS::SMHDR_SZ + GuidPrefixOffset,
2082  encoded_buffer.get_buffer() + GuidPrefixOffset,
2083  sizeof(DCPS::GuidPrefix_t))) {
2084  return CommonUtilities::set_security_error(ex, -12, 0, "Header GUID Prefix doesn't match INFO_SRC");
2085  }
2086 
2087  plain_buffer.length(transformed.length() - RTPS::SMHDR_SZ);
2088  std::memcpy(plain_buffer.get_buffer(), RTPS::PROTOCOL_RTPS, sizeof RTPS::PROTOCOL_RTPS);
2089  std::memcpy(plain_buffer.get_buffer() + sizeof RTPS::PROTOCOL_RTPS,
2090  transformed.get_buffer() + RTPS::SMHDR_SZ + sizeof RTPS::PROTOCOL_RTPS,
2091  plain_buffer.length() - sizeof RTPS::PROTOCOL_RTPS);
2092  return true;
2093 }
2094 
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  encoded_rtps_submessage.length());
2103  mb_in.wr_ptr(encoded_rtps_submessage.length());
2104  Serializer de_ser(&mb_in, common_encoding);
2105  ACE_CDR::Octet type, flags;
2106  // SEC_PREFIX
2107  de_ser >> ACE_InputCDR::to_octet(type);
2108  de_ser >> ACE_InputCDR::to_octet(flags);
2109  de_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
2110  ACE_CDR::UShort octetsToNext;
2111  de_ser >> octetsToNext;
2112  CryptoHeader ch = CryptoHeader();
2113  de_ser.endianness(ENDIAN_BIG);
2114  de_ser >> ch;
2115  de_ser.skip(octetsToNext - CRYPTO_HEADER_LENGTH);
2116  if (!de_ser.good_bit()) {
2118  "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
2119  "Failed to deserialize SEC_PREFIX\n"));
2120  return false;
2121  }
2122 
2123  // Next submessage, SEC_BODY if encrypted
2124  de_ser >> ACE_InputCDR::to_octet(type);
2125  de_ser >> ACE_InputCDR::to_octet(flags);
2126  de_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
2127  de_ser >> octetsToNext;
2128  if (!de_ser.good_bit()) {
2130  "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
2131  "Failed to deserialize next submessage\n"));
2132  return false;
2133  }
2134 
2135  Message_Block_Ptr mb_footer(mb_in.duplicate());
2136  mb_footer->rd_ptr(octetsToNext);
2137  // SEC_POSTFIX
2138  Serializer post_ser(mb_footer.get(), common_encoding);
2139  post_ser >> ACE_InputCDR::to_octet(type);
2140  post_ser >> ACE_InputCDR::to_octet(flags);
2141  post_ser.swap_bytes((flags & RTPS::FLAG_E) != ACE_CDR_BYTE_ORDER);
2142  ACE_CDR::UShort postfixOctetsToNext;
2143  post_ser >> postfixOctetsToNext;
2144  CryptoFooter cf;
2145  de_ser.endianness(ENDIAN_BIG);
2146  post_ser >> cf;
2147  if (!post_ser.good_bit()) {
2149  "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
2150  "Failed to deserialize SEC_POST\n"));
2151  return false;
2152  }
2153 
2155  const KeyTable_t::const_iterator keys_iter = keys_.find(sender_handle);
2156  if (keys_iter == keys_.end()) {
2157  return CommonUtilities::set_security_error(ex, -2, 3, "Crypto Key not found");
2158  }
2159 
2160  const KeySeq& keyseq = keys_iter->second;
2161  for (unsigned int i = 0; i < keyseq.length(); ++i) {
2162  if (matches(keyseq[i], ch)) {
2163  const KeyId_t sKey = std::make_pair(sender_handle, i);
2164 
2165  if (encrypts(keyseq[i])) {
2166  de_ser.endianness(ENDIAN_BIG);
2167  ACE_CDR::ULong n;
2168  if (!(de_ser >> n)) {
2170  "(%P|%t) ERROR: CryptoBuiltInImpl::decode_submessage: "
2171  "Failed to deserialize content size(?)\n"));
2172  return false;
2173  }
2174  return decrypt(keyseq[i], sessions_[sKey], mb_in.rd_ptr(), n, ch, cf,
2175  plain_rtps_submessage, ex);
2176 
2177  } else if (authenticates(keyseq[i])) {
2178  return verify(keyseq[i], sessions_[sKey], mb_in.rd_ptr() - RTPS::SMHDR_SZ,
2179  RTPS::SMHDR_SZ + octetsToNext, ch, cf, plain_rtps_submessage, ex);
2180 
2181  } else {
2182  return CommonUtilities::set_security_error(ex, -2, 2, "Key transform kind unrecognized");
2183  }
2184  }
2185  }
2186 
2187  return CommonUtilities::set_security_error(ex, -2, 1, "Crypto Key not found");
2188 }
2189 
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  if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
2202  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datawriter handle");
2203  }
2204 
2206  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  return decode_submessage(plain_rtps_submessage, encoded_rtps_submessage,
2212  sending_datawriter_crypto, ex);
2213 }
2214 
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  if (DDS::HANDLE_NIL == sending_datareader_crypto) {
2223  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 
2231  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  return decode_submessage(plain_rtps_submessage, encoded_rtps_submessage,
2237  sending_datareader_crypto, ex);
2238 }
2239 
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  if (DDS::HANDLE_NIL == sending_datawriter_crypto) {
2254  return CommonUtilities::set_security_error(ex, -1, 0, "Invalid Datawriter handle");
2255  }
2256 
2258  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 
2264  const KeyTable_t::const_iterator iter = keys_.find(sending_datawriter_crypto);
2265  if (iter == keys_.end()) {
2266  return CommonUtilities::set_security_error(ex, -1, 1, "No key for DataWriter crypto handle");
2267  }
2268  const EncryptOptions_t::const_iterator eo_iter = encrypt_options_.find(sending_datawriter_crypto);
2269  if (eo_iter == encrypt_options_.end()) {
2270  return CommonUtilities::set_security_error(ex, -1, 0, "Datawriter handle lacks encrypt options");
2271  }
2272  if (!eo_iter->second.payload_) {
2273  plain_buffer = encoded_buffer;
2275  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  return true;
2280  }
2281 
2282  ACE_Message_Block mb_in(to_mb(encoded_buffer.get_buffer()),
2283  encoded_buffer.length());
2284  mb_in.wr_ptr(encoded_buffer.length());
2285  Serializer de_ser(&mb_in, common_encoding);
2286  CryptoHeader ch = CryptoHeader();
2287  if (!(de_ser >> ch)) {
2288  return CommonUtilities::set_security_error(ex, -3, 4, "Failed to deserialize CryptoHeader");
2289  }
2290 
2291  const KeySeq& keyseq = iter->second;
2292  for (unsigned int i = 0; i < keyseq.length(); ++i) {
2293  if (matches(keyseq[i], ch)) {
2294  const KeyId_t sKey = std::make_pair(sending_datawriter_crypto, i);
2295  if (encrypts(keyseq[i])) {
2296  ACE_CDR::ULong n;
2297  if (!(de_ser >> n)) {
2298  return CommonUtilities::set_security_error(ex, -3, 5, "Failed to deserialize CryptoContent length");
2299  }
2300  const char* const ciphertext = mb_in.rd_ptr();
2301  if (!de_ser.skip(n)) {
2302  return CommonUtilities::set_security_error(ex, -3, 7, "Failed to locate CryptoFooter");
2303  }
2304  CryptoFooter cf;
2305  if (!(de_ser >> cf)) {
2306  return CommonUtilities::set_security_error(ex, -3, 6, "Failed to deserialize CryptoFooter");
2307  }
2308  return decrypt(keyseq[i], sessions_[sKey], ciphertext, n, ch, cf, plain_buffer, ex);
2309 
2310  } else if (authenticates(keyseq[i])) {
2311  return CommonUtilities::set_security_error(ex, -3, 3, "Auth-only payload "
2312  "transformation not supported "
2313  "(DDSSEC12-59)");
2314 
2315  } else {
2316  return CommonUtilities::set_security_error(ex, -3, 2, "Key transform kind unrecognized");
2317  }
2318  }
2319  }
2320 
2321  return CommonUtilities::set_security_error(ex, -3, 1, "Crypto Key not found");
2322 }
2323 
2324 }
2325 }
2326 
virtual DDS::Security::DatawriterCryptoHandle register_matched_remote_datawriter(DDS::Security::DatareaderCryptoHandle local_datareader_crypto_handle, DDS::Security::ParticipantCryptoHandle remote_participant_crypt, DDS::Security::SharedSecretHandle *shared_secret, DDS::Security::SecurityException &ex)
ACE_Byte Octet
virtual bool encode_datawriter_submessage(DDS::OctetSeq &encoded_rtps_submessage, const DDS::OctetSeq &plain_rtps_submessage, DDS::Security::DatawriterCryptoHandle sending_datawriter_crypto, const DDS::Security::DatareaderCryptoHandleSeq &receiving_datareader_crypto_list, CORBA::Long &receiving_datareader_crypto_list_index, DDS::Security::SecurityException &ex)
virtual bool create_local_datawriter_crypto_tokens(DDS::Security::DatawriterCryptoTokenSeq &local_datawriter_crypto_tokens, DDS::Security::DatawriterCryptoHandle local_datawriter_crypto, DDS::Security::DatareaderCryptoHandle remote_datareader_crypto, DDS::Security::SecurityException &ex)
#define ACE_DEBUG(X)
ACE_CDR::Long Long
virtual bool decode_rtps_message(DDS::OctetSeq &plain_buffer, const DDS::OctetSeq &encoded_buffer, DDS::Security::ParticipantCryptoHandle receiving_participant_crypto, DDS::Security::ParticipantCryptoHandle sending_participant_crypto, DDS::Security::SecurityException &ex)
virtual bool decode_serialized_payload(DDS::OctetSeq &plain_buffer, const DDS::OctetSeq &encoded_buffer, const DDS::OctetSeq &inline_qos, DDS::Security::DatareaderCryptoHandle receiving_datareader_crypto, DDS::Security::DatawriterCryptoHandle sending_datawriter_crypto, DDS::Security::SecurityException &ex)
virtual bool set_remote_datawriter_crypto_tokens(DDS::Security::DatareaderCryptoHandle local_datareader_crypto, DDS::Security::DatawriterCryptoHandle remote_datawriter_crypto, const DDS::Security::DatawriterCryptoTokenSeq &remote_datawriter_tokens, DDS::Security::SecurityException &ex)
const octet CRYPTO_TRANSFORMATION_KIND_AES256_GCM
#define ACE_ERROR(X)
sequence< octet, 32 > KeyOctetSeq
BinaryPropertySeq binary_properties
EVP_PKEY * pkey_
const InstanceHandle_t HANDLE_NIL
const octet FLAG_E
Definition: RtpsCore.idl:521
const ACE_CDR::UShort INFO_SRC_SZ
Definition: MessageTypes.h:110
const unsigned long FLAG_IS_PAYLOAD_ENCRYPTED
virtual bool have_local_datawriter_crypto_tokens(DDS::Security::DatawriterCryptoHandle local_datawriter_crypto, DDS::Security::DatareaderCryptoHandle remote_datareader_crypto)
const ACE_CDR::UShort RTPSHDR_SZ
Definition: MessageTypes.h:105
SubmessageHeader submessageHeader() const
Definition: MessageParser.h:34
bool authtag(const KeyMaterial &master, Session &sess, const DDS::OctetSeq &plain, CryptoHeader &header, CryptoFooter &footer, DDS::Security::SecurityException &ex)
bool chlookup
Print Verbose Search Info About Getting the Crypto Handle from a Key id.
Definition: debug.h:142
int hash(const std::vector< const DDS::OctetSeq *> &src, DDS::OctetSeq &dst)
virtual bool encode_datareader_submessage(DDS::OctetSeq &encoded_rtps_submessage, const DDS::OctetSeq &plain_rtps_submessage, DDS::Security::DatareaderCryptoHandle sending_datareader_crypto, const DDS::Security::DatawriterCryptoHandleSeq &receiving_datawriter_crypto_list, DDS::Security::SecurityException &ex)
const unsigned long FLAG_IS_SUBMESSAGE_ENCRYPTED
sequence< DatareaderCryptoHandle > DatareaderCryptoHandleSeq
const octet CRYPTO_TRANSFORMATION_KIND_AES128_GCM
bool skip(size_t n, int size=1)
Definition: Serializer.inl:443
virtual bool preprocess_secure_submsg(DDS::Security::DatawriterCryptoHandle &datawriter_crypto, DDS::Security::DatareaderCryptoHandle &datareader_crypto, DDS::Security::SecureSubmessageCategory_t &secure_submessage_category, const DDS::OctetSeq &encoded_rtps_submessage, DDS::Security::ParticipantCryptoHandle receiving_participant_crypto, DDS::Security::ParticipantCryptoHandle sending_participant_crypto, DDS::Security::SecurityException &ex)
sequence< octet > key
String to_dds_string(unsigned short to_convert)
const ACE_CDR::Octet PROTOCOL_RTPS[]
Definition: MessageTypes.h:58
bool decrypt(const KeyMaterial &master, Session &sess, const char *ciphertext, unsigned int n, const CryptoHeader &header, const CryptoFooter &footer, DDS::OctetSeq &out, DDS::Security::SecurityException &ex)
octet CryptoTransformKeyId[4]
sequence< DatawriterCryptoHandle > DatawriterCryptoHandleSeq
virtual bool have_local_participant_crypto_tokens(DDS::Security::ParticipantCryptoHandle local_participant_crypto, DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
virtual bool decode_datareader_submessage(DDS::OctetSeq &plain_rtps_submessage, const DDS::OctetSeq &encoded_rtps_submessage, DDS::Security::DatawriterCryptoHandle receiving_datawriter_crypto, DDS::Security::DatareaderCryptoHandle sending_datareader_crypto, DDS::Security::SecurityException &ex)
struct evp_pkey_st EVP_PKEY
const char * ctk_to_dds_string(const CryptoTransformKind &keyKind)
unsigned long PluginEndpointSecurityAttributesMask
KeyMaterial_AES_GCM_GMAC_Seq KeySeq
virtual DDS::Security::DatareaderCryptoHandle register_matched_remote_datareader(DDS::Security::DatawriterCryptoHandle local_datawriter_crypto_handle, DDS::Security::ParticipantCryptoHandle remote_participant_crypto, DDS::Security::SharedSecretHandle *shared_secret, bool relay_only, DDS::Security::SecurityException &ex)
#define ACE_CDR_BYTE_ORDER
bool operator==(const DisjointSequence::OrderedRanges< T > &a, const DisjointSequence::OrderedRanges< T > &b)
KeyOctetSeq get_key(const KeyMaterial &master, const CryptoHeader &header)
void serialized_size(const Encoding &encoding, size_t &size, const SequenceNumber &)
const size_t uint32_cdr_size
Definition: Serializer.h:96
char * rd_ptr(void) const
const octet CRYPTO_TRANSFORMATION_KIND_AES128_GMAC
virtual bool create_local_participant_crypto_tokens(DDS::Security::ParticipantCryptoTokenSeq &local_participant_crypto_tokens, DDS::Security::ParticipantCryptoHandle local_participant_crypto, DDS::Security::ParticipantCryptoHandle remote_participant_crypto, DDS::Security::SecurityException &ex)
virtual bool have_local_datareader_crypto_tokens(DDS::Security::DatareaderCryptoHandle local_datareader_crypto, DDS::Security::DatawriterCryptoHandle remote_datawriter_crypto)
const ACE_CDR::UShort SMHDR_SZ
Definition: MessageTypes.h:106
PluginEndpointSecurityAttributesMask plugin_endpoint_attributes
virtual DDS::Security::ParticipantCryptoHandle register_local_participant(DDS::Security::IdentityHandle participant_identity, DDS::Security::PermissionsHandle participant_permissions, const DDS::PropertySeq &participant_properties, const DDS::Security::ParticipantSecurityAttributes &participant_security_attributes, DDS::Security::SecurityException &ex)
CryptoTokenSeq ParticipantCryptoTokenSeq
bool write_octet_array(const ACE_CDR::Octet *x, ACE_CDR::ULong length)
Definition: Serializer.inl:697
#define OPENDDS_STRING
bool encode_submessage(DDS::OctetSeq &encoded_rtps_submessage, const DDS::OctetSeq &plain_rtps_submessage, DDS::Security::NativeCryptoHandle sender_handle, DDS::Security::SecurityException &ex)
readonly attribute OctetSeq challenge2
std::pair< DDS::Security::NativeCryptoHandle, DDS::Security::NativeCryptoHandle > HandlePair_t
PluginParticipantSecurityAttributesMask plugin_participant_attributes
const unsigned long TransformKindIndex
LM_DEBUG
NativeCryptoHandle DatawriterCryptoHandle
virtual bool have_remote_datareader_crypto_tokens(DDS::Security::DatawriterCryptoHandle local_datawriter_crypto, DDS::Security::DatareaderCryptoHandle remote_datareader_crypto)
virtual bool decode_datawriter_submessage(DDS::OctetSeq &plain_rtps_submessage, const DDS::OctetSeq &encoded_rtps_submessage, DDS::Security::DatareaderCryptoHandle receiving_datareader_crypto, DDS::Security::DatawriterCryptoHandle sending_datawriter_crypto, DDS::Security::SecurityException &ex)
CryptoTokenSeq DatareaderCryptoTokenSeq
Class to serialize and deserialize data for DDS.
Definition: Serializer.h:369
void clear_endpoint_data(DDS::Security::NativeCryptoHandle handle)
const long OPENDDS_EXCEPTION_CODE_NO_KEY
size_t length() const
Number of bytes left to read in message block chain.
Definition: Serializer.inl:437
virtual bool encode_rtps_message(DDS::OctetSeq &encoded_rtps_message, const DDS::OctetSeq &plain_rtps_message, DDS::Security::ParticipantCryptoHandle sending_participant_crypto, const DDS::Security::ParticipantCryptoHandleSeq &receiving_participant_crypto_list, CORBA::Long &receiving_participant_crypto_list_index, DDS::Security::SecurityException &ex)
bool verify(const KeyMaterial &master, Session &sess, const char *in, unsigned int n, const CryptoHeader &header, const CryptoFooter &footer, DDS::OctetSeq &out, DDS::Security::SecurityException &ex)
Christopher Diggins *renamed files *fixing compilation errors *adding Visual C project file *removed make Max Lybbert *removed references to missing and unused header
Definition: CHANGELOG.txt:8
Endianness endianness() const
Definition: Serializer.inl:220
ACE_UINT16 UShort
NativeCryptoHandle DatareaderCryptoHandle
const Encoding common_encoding(Encoding::KIND_XCDR1, ENDIAN_BIG)
unique_ptr< ACE_Message_Block, Message_Block_Deleter > Message_Block_Ptr
virtual bool have_remote_participant_crypto_tokens(DDS::Security::ParticipantCryptoHandle local_participant_crypto, DDS::Security::ParticipantCryptoHandle remote_participant_crypto)
String_Manager_T< CORBA::Char > String_Manager
bool encrypt(const KeyMaterial &master, Session &sess, const DDS::OctetSeq &plain, CryptoHeader &header, CryptoFooter &footer, DDS::OctetSeq &out, DDS::Security::SecurityException &ex)
bool bookkeeping
Generation and Tracking of Crypto Handles and Keys.
Definition: debug.h:136
virtual bool have_remote_datawriter_crypto_tokens(DDS::Security::DatareaderCryptoHandle local_datareader_crypto, DDS::Security::DatawriterCryptoHandle remote_datawriter_crypto)
virtual DDS::Security::DatawriterCryptoHandle register_local_datawriter(DDS::Security::ParticipantCryptoHandle participant_crypto, const DDS::PropertySeq &datawriter_properties, const DDS::Security::EndpointSecurityAttributes &datawriter_security_attributes, DDS::Security::SecurityException &ex)
virtual bool unregister_datareader(DDS::Security::DatareaderCryptoHandle datareader_crypto_handle, DDS::Security::SecurityException &ex)
DDS::PropertySeq PropertySeq
Definition: RtpsCore.idl:49
char * wr_ptr(void) const
sequence< octet > OctetSeq
Definition: DdsDcpsCore.idl:64
ACE_UINT32 ULong
void encauth_setup(const KeyMaterial &master, Session &sess, const DDS::OctetSeq &plain, CryptoHeader &header)
OpenDDS_Dcps_Export void align(size_t &value, size_t by)
Align "value" by "by" if it&#39;s not already.
Definition: Serializer.inl:23
virtual DDS::Security::DatareaderCryptoHandle register_local_datareader(DDS::Security::ParticipantCryptoHandle participant_crypto, const DDS::PropertySeq &datareader_properties, const DDS::Security::EndpointSecurityAttributes &datareader_security_attributes, DDS::Security::SecurityException &ex)
octet CryptoTransformKind[4]
const char *const name
Definition: debug.cpp:60
const octet CRYPTO_TRANSFORMATION_KIND_AES256_GMAC
EVP_MD_CTX * ctx_
ACE_TEXT("TCP_Factory")
virtual bool set_remote_participant_crypto_tokens(DDS::Security::ParticipantCryptoHandle local_participant_crypto, DDS::Security::ParticipantCryptoHandle remote_participant_crypto, const DDS::Security::ParticipantCryptoTokenSeq &remote_participant_tokens, DDS::Security::SecurityException &ex)
void swap_bytes(bool do_swap)
Definition: Serializer.inl:403
OPENDDS_STRING ctki_to_dds_string(const CryptoTransformKeyId &keyId)
virtual bool return_crypto_tokens(const DDS::Security::CryptoTokenSeq &crypto_tokens, DDS::Security::SecurityException &ex)
#define EVP_MD_CTX_new
void push_back(Seq &seq, const typename Seq::value_type &val)
std::vector-style push_back() for CORBA Sequences
Definition: Util.h:138
virtual bool unregister_datawriter(DDS::Security::DatawriterCryptoHandle datawriter_crypto_handle, DDS::Security::SecurityException &ex)
bool decode_submessage(DDS::OctetSeq &plain_rtps_submessage, const DDS::OctetSeq &encoded_rtps_submessage, DDS::Security::NativeCryptoHandle sender_handle, DDS::Security::SecurityException &ex)
IV_SuffixType initialization_vector_suffix
virtual bool create_local_datareader_crypto_tokens(DDS::Security::DatareaderCryptoTokenSeq &local_datareader_crypto_tokens, DDS::Security::DatareaderCryptoHandle local_datareader_crypto, DDS::Security::DatawriterCryptoHandle remote_datawriter_crypto, DDS::Security::SecurityException &ex)
bool align_w(size_t alignment)
Definition: Serializer.inl:830
readonly attribute OctetSeq challenge1
#define EVP_MD_CTX_free
const long OPENDDS_EXCEPTION_MINOR_CODE_NO_KEY
octet GuidPrefix_t[12]
Definition: DdsDcpsGuid.idl:19
void clear_common_data(DDS::Security::NativeCryptoHandle handle)
sequence< ParticipantCryptoHandle > ParticipantCryptoHandleSeq
virtual bool set_remote_datareader_crypto_tokens(DDS::Security::DatawriterCryptoHandle local_datawriter_crypto, DDS::Security::DatareaderCryptoHandle remote_datareader_crypto, const DDS::Security::DatareaderCryptoTokenSeq &remote_datareader_tokens, DDS::Security::SecurityException &ex)
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
std::multimap< DDS::Security::ParticipantCryptoHandle, EntityInfo > participant_to_entity_
std::pair< DDS::Security::NativeCryptoHandle, unsigned int > KeyId_t
bool showkeys
Print the Key when Generating it or Using It.
Definition: debug.h:139
virtual bool encode_serialized_payload(DDS::OctetSeq &encoded_buffer, DDS::OctetSeq &extra_inline_qos, const DDS::OctetSeq &plain_buffer, DDS::Security::DatawriterCryptoHandle sending_datawriter_crypto, DDS::Security::SecurityException &ex)
readonly attribute OctetSeq sharedSecret
const char * current() const
Definition: MessageParser.h:36
void openssl_init()
Definition: OpenSSL_init.h:17
void openssl_cleanup()
Definition: OpenSSL_init.h:22
const GuidVendorId_t VENDORID_OCI
Vendor Id value specified for OCI is used for OpenDDS.
Definition: GuidUtils.h:29
bool set_security_error(DDS::Security::SecurityException &ex, int code, int minor_code, const char *message)
sequence< CryptoToken > CryptoTokenSeq
sequence< KeyMaterial_AES_GCM_GMAC > KeyMaterial_AES_GCM_GMAC_Seq
virtual bool unregister_participant(DDS::Security::ParticipantCryptoHandle participant_crypto_handle, DDS::Security::SecurityException &ex)
#define EVP_CTRL_AEAD_GET_TAG
const ParticipantSecurityAttributesMask PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED
LM_ERROR
DCPS::Serializer & serializer()
Definition: MessageParser.h:38
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
CryptoTokenSeq DatawriterCryptoTokenSeq
CryptoTransformIdentifier transform_identifier
bool fake_encryption
Disable all encryption for security, even the required builtin encryption.
Definition: debug.h:146
OpenDDS_Dcps_Export SecurityDebug security_debug
Definition: debug.cpp:32
DDS::Security::NativeCryptoHandle generate_handle_i()
const size_t SM_ALIGN
Alignment of RTPS Submessage.
Definition: MessageTypes.h:113
virtual DDS::Security::ParticipantCryptoHandle register_matched_remote_participant(DDS::Security::ParticipantCryptoHandle local_participant_crypto_handle, DDS::Security::IdentityHandle remote_participant_identity, DDS::Security::PermissionsHandle remote_participant_permissions, DDS::Security::SharedSecretHandle *shared_secret, DDS::Security::SecurityException &ex)
DDS::Security::NativeCryptoHandle generate_handle()