LCOV - code coverage report
Current view: top level - DCPS/security/SSL - Utils.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 129 88.4 %
Date: 2023-04-30 01:32:43 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Distributed under the OpenDDS License.
       3             :  * See: http://www.OpenDDS.org/license.html
       4             :  */
       5             : 
       6             : #include "Utils.h"
       7             : 
       8             : #include "Err.h"
       9             : 
      10             : #include <dds/DCPS/Serializer.h>
      11             : #include <dds/DCPS/GuidUtils.h>
      12             : 
      13             : #include <dds/DdsDcpsCoreTypeSupportImpl.h>
      14             : 
      15             : #include <openssl/evp.h>
      16             : #include <openssl/rand.h>
      17             : #include <openssl/err.h>
      18             : #include "../OpenSSL_legacy.h"  // Must come after all other OpenSSL includes
      19             : 
      20             : #include <vector>
      21             : #include <utility>
      22             : #include <cstdio>
      23             : 
      24             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      25             : 
      26             : namespace OpenDDS {
      27             : namespace Security {
      28             : namespace SSL {
      29             : 
      30             : using DCPS::Serializer;
      31             : using DCPS::Encoding;
      32             : using DCPS::serialized_size;
      33             : 
      34             : namespace {
      35          48 :   Encoding get_common_encoding() {
      36          48 :     Encoding encoding(Encoding::KIND_XCDR1, DCPS::ENDIAN_BIG);
      37          48 :     return encoding;
      38             :   }
      39             : }
      40             : 
      41          46 : int make_adjusted_guid(const OpenDDS::DCPS::GUID_t& src,
      42             :                        OpenDDS::DCPS::GUID_t& dst,
      43             :                        const Certificate& target)
      44             : {
      45          46 :   dst = OpenDDS::DCPS::GUID_UNKNOWN;
      46          46 :   dst.entityId = src.entityId;
      47             : 
      48          46 :   std::vector<unsigned char> hash;
      49          46 :   int result = target.subject_name_digest(hash);
      50             : 
      51          46 :   if (result == 0 && hash.size() >= 6) {
      52          46 :     unsigned char* bytes = reinterpret_cast<unsigned char*>(&dst);
      53             : 
      54         322 :     for (size_t i = 0; i < 6; ++i) {  // First 6 bytes of guid prefix
      55         276 :       bytes[i] = offset_1bit(&hash[0], i);
      56             :     }
      57             : 
      58          46 :     bytes[0] |= 0x80;
      59             : 
      60             :     // Last 6 bytes of guid prefix = hash of src guid (candidate guid)
      61             : 
      62          46 :     unsigned char hash2[EVP_MAX_MD_SIZE] = {0};
      63          46 :     unsigned int len = 0u;
      64             : 
      65          46 :     EVP_MD_CTX* hash_ctx = EVP_MD_CTX_new();
      66          46 :     if (hash_ctx) {
      67          46 :       EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
      68          46 :       EVP_DigestUpdate(hash_ctx, &src, sizeof(OpenDDS::DCPS::GUID_t));
      69          46 :       EVP_DigestFinal_ex(hash_ctx, hash2, &len);
      70          46 :       if (len > 5) {
      71          46 :         std::memcpy(bytes + 6, hash2, 6);
      72             :       } else {
      73           0 :         result = 1;
      74             :       }
      75             : 
      76          46 :       EVP_MD_CTX_free(hash_ctx);
      77             :     }
      78             :   }
      79             : 
      80          46 :   return result;
      81          46 : }
      82             : 
      83             : template <size_t Bits>
      84          17 : int make_nonce(std::vector<unsigned char>& nonce)
      85             : {
      86          17 :   nonce.clear();
      87             : 
      88          17 :   unsigned char tmp[Bits / 8] = { 0 };
      89             : 
      90          17 :   if (RAND_bytes(tmp, sizeof tmp) == 1) {
      91          17 :     nonce.insert(nonce.begin(), tmp, tmp + sizeof tmp);
      92             : 
      93          17 :     return 0;
      94             : 
      95             :   } else {
      96           0 :     unsigned long err = ERR_get_error();
      97           0 :     char msg[256] = { 0 };
      98           0 :     ERR_error_string_n(err, msg, sizeof(msg));
      99             : 
     100           0 :     ACE_ERROR((LM_ERROR,
     101             :                ACE_TEXT("(%P|%t) SSL::make_nonce: ERROR '%C' returned by RAND_bytes(...)\n"),
     102             :                msg));
     103             :   }
     104             : 
     105           0 :   return 1;
     106             : }
     107             : 
     108           1 : int make_nonce_256(std::vector<unsigned char>& nonce)
     109             : {
     110           1 :   return make_nonce<256>(nonce);
     111             : }
     112             : 
     113          16 : int make_nonce_256(DDS::OctetSeq& nonce)
     114             : {
     115             :   /* A bit slower but the impl. for vectors is already complete */
     116          16 :   std::vector<unsigned char> tmp;
     117          16 :   int err = make_nonce<256>(tmp);
     118          16 :   if (!err) {
     119          16 :     nonce.length(static_cast<unsigned int>(tmp.size()));
     120         528 :     for (size_t i = 0; i < tmp.size(); ++i) {
     121         512 :       nonce[static_cast<unsigned int>(i)] = tmp[i];
     122             :     }
     123             :   }
     124          16 :   return err;
     125          16 : }
     126             : 
     127         348 : unsigned char offset_1bit(const unsigned char array[], size_t i)
     128             : {
     129         348 :   return (array[i] >> 1) | (i == 0 ? 0 : ((array[i - 1] & 1) ? 0x80 : 0));
     130             : }
     131             : 
     132          14 : int hash(const std::vector<const DDS::OctetSeq*>& src, DDS::OctetSeq& dst)
     133             : {
     134          14 :   EVP_MD_CTX* hash_ctx = EVP_MD_CTX_new();
     135          14 :   if (!hash_ctx) {
     136           0 :     OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
     137           0 :     return 1;
     138             :   }
     139             : 
     140          14 :   EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
     141             : 
     142          14 :   unsigned char hash[EVP_MAX_MD_SIZE] = { 0 };
     143          14 :   unsigned int len = 0u;
     144             : 
     145          14 :   std::vector<const DDS::OctetSeq*>::const_iterator i, n = src.end();
     146          28 :   for (i = src.begin(); i != n; ++i) {
     147          14 :     EVP_DigestUpdate(hash_ctx, (*i)->get_buffer(), (*i)->length());
     148             :   }
     149             : 
     150          14 :   EVP_DigestFinal_ex(hash_ctx, hash, &len);
     151             : 
     152          14 :   dst.length(len);
     153          14 :   std::memcpy(dst.get_buffer(), hash, len);
     154             : 
     155          14 :   EVP_MD_CTX_free(hash_ctx);
     156             : 
     157          14 :   return 0;
     158             : }
     159             : 
     160             : class hash_serialized_impl
     161             : {
     162             : public:
     163          26 :   hash_serialized_impl()
     164          26 :     : hash_ctx(EVP_MD_CTX_new())
     165             :   {
     166          26 :     if (!hash_ctx) {
     167           0 :       OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
     168             :     }
     169          26 :   }
     170             : 
     171          26 :   ~hash_serialized_impl()
     172             :   {
     173          26 :     if (hash_ctx) {
     174          26 :       EVP_MD_CTX_free(hash_ctx);
     175             :     }
     176          26 :   }
     177             : 
     178          26 :   int operator()(const DDS::BinaryPropertySeq& src, DDS::OctetSeq& dst)
     179             :   {
     180          26 :     if (!hash_ctx) return 1;
     181             : 
     182          26 :     EVP_DigestInit_ex(hash_ctx, EVP_sha256(), 0);
     183             : 
     184          26 :     const Encoding encoding = get_common_encoding();
     185          26 :     size_t size = 0;
     186          26 :     serialized_size(encoding, size, src);
     187          26 :     ACE_Message_Block buffer(size);
     188          26 :     Serializer serializer(&buffer, encoding);
     189          26 :     if (serializer << src) {
     190          26 :       EVP_DigestUpdate(hash_ctx, buffer.rd_ptr(), buffer.length());
     191             : 
     192          26 :       dst.length(EVP_MAX_MD_SIZE);
     193             : 
     194          26 :       unsigned int newlen = 0u;
     195          26 :       EVP_DigestFinal_ex(hash_ctx, dst.get_buffer(), &newlen);
     196             : 
     197          26 :       dst.length(newlen);
     198             : 
     199             :     } else {
     200           0 :       ACE_ERROR((LM_ERROR,
     201             :                  ACE_TEXT("(%P|%t) SSL::hash_serialized_impl::operator(): ERROR, failed to "
     202             :                           "serialize binary-property-sequence\n")));
     203             : 
     204           0 :       return 1;
     205             :     }
     206             : 
     207          26 :     return 0;
     208          26 :   }
     209             : 
     210             : private:
     211             :   EVP_MD_CTX* hash_ctx;
     212             : };
     213             : 
     214          26 : int hash_serialized(const DDS::BinaryPropertySeq& src, DDS::OctetSeq& dst)
     215             : {
     216          26 :   hash_serialized_impl hash;
     217          52 :   return hash(src, dst);
     218          26 : }
     219             : 
     220          12 : int sign_serialized(const DDS::BinaryPropertySeq& src,
     221             :                     const PrivateKey& key, DDS::OctetSeq& dst)
     222             : {
     223          12 :   const Encoding encoding = get_common_encoding();
     224          12 :   size_t size = 0;
     225          12 :   serialized_size(encoding, size, src);
     226             : 
     227          12 :   DDS::OctetSeq tmp;
     228          12 :   tmp.length(static_cast<unsigned int>(size));
     229          24 :   ACE_Message_Block buffer(reinterpret_cast<const char*>(tmp.get_buffer()),
     230          12 :                            tmp.length());
     231          12 :   Serializer serializer(&buffer, encoding);
     232          12 :   if (!(serializer << src)) {
     233           0 :     ACE_ERROR((LM_ERROR,
     234             :                ACE_TEXT("(%P|%t) SSL::sign_serialized: ERROR, failed to serialize "
     235             :                         "binary-property-sequence\n")));
     236             : 
     237           0 :     return 1;
     238             :   }
     239             : 
     240          12 :   std::vector<const DDS::OctetSeq*> sign_these;
     241          12 :   sign_these.push_back(&tmp);
     242             : 
     243          12 :   return key.sign(sign_these, dst);
     244          12 : }
     245             : 
     246          10 : int verify_serialized(const DDS::BinaryPropertySeq& src,
     247             :                       const Certificate& key,
     248             :                       const DDS::OctetSeq& signed_data)
     249             : {
     250          10 :   const Encoding encoding = get_common_encoding();
     251          10 :   size_t size = 0;
     252          10 :   serialized_size(encoding, size, src);
     253             : 
     254          10 :   DDS::OctetSeq tmp;
     255          10 :   tmp.length(static_cast<unsigned int>(size));
     256          20 :   ACE_Message_Block buffer(reinterpret_cast<const char*>(tmp.get_buffer()),
     257          10 :                            tmp.length());
     258          10 :   Serializer serializer(&buffer, encoding);
     259          10 :   if (!(serializer << src)) {
     260           0 :     ACE_ERROR((LM_ERROR,
     261             :                ACE_TEXT("(%P|%t) SSL::verify_serialized: ERROR, failed to serialize binary-property-sequence\n")));
     262             : 
     263           0 :     return 1;
     264             :   }
     265             : 
     266          10 :   std::vector<const DDS::OctetSeq*> verify_these;
     267          10 :   verify_these.push_back(&tmp);
     268             : 
     269          10 :   return key.verify_signature(signed_data, verify_these);
     270          10 : }
     271             : 
     272             : }  // namespace SSL
     273             : }  // namespace Security
     274             : }  // namespace OpenDDS
     275             : 
     276             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16