LCOV - code coverage report
Current view: top level - DCPS/security/SSL - Certificate.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 211 301 70.1 %
Date: 2023-04-30 01:32:43 Functions: 29 31 93.5 %

          Line data    Source code
       1             : /*
       2             :  * Distributed under the OpenDDS License.
       3             :  * See: http://www.OpenDDS.org/license.html
       4             :  */
       5             : 
       6             : #include "Certificate.h"
       7             : #include "dds/DCPS/security/CommonUtilities.h"
       8             : #include "Err.h"
       9             : #include <algorithm>
      10             : #include <cstring>
      11             : #include <fstream>
      12             : #include <iterator>
      13             : #include <cerrno>
      14             : #include <openssl/pem.h>
      15             : #include <openssl/x509v3.h>
      16             : #include "../OpenSSL_legacy.h"  // Must come after all other OpenSSL includes
      17             : #include <sstream>
      18             : 
      19             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      20             : 
      21             : namespace OpenDDS {
      22             : namespace Security {
      23             : namespace SSL {
      24             : 
      25         220 : Certificate::Certificate(const std::string& uri,
      26         220 :                          const std::string& password)
      27         220 :   : x_(0), original_bytes_(), dsign_algo_("")
      28             : {
      29         220 :   DDS::Security::SecurityException ex;
      30         220 :   if (! load(ex, uri, password)) {
      31           1 :     ACE_ERROR((LM_WARNING, "(%P|%t) %C\n", ex.message.in()));
      32             :   }
      33         220 : }
      34             : 
      35           6 : Certificate::Certificate(const DDS::OctetSeq& src)
      36           6 :   : x_(0), original_bytes_(), dsign_algo_("")
      37             : {
      38           6 :   deserialize(src);
      39           6 : }
      40             : 
      41          20 : Certificate::Certificate()
      42          20 :   : x_(0), original_bytes_(), dsign_algo_("")
      43             : {
      44          20 : }
      45             : 
      46           2 : Certificate::Certificate(const Certificate& other)
      47           2 :   : x_(0), original_bytes_(), dsign_algo_("")
      48             : {
      49           2 :   if (0 < other.original_bytes_.length()) {
      50           2 :     deserialize(other.original_bytes_);
      51             :   }
      52           2 : }
      53             : 
      54         332 : Certificate::~Certificate()
      55             : {
      56         248 :   if (x_) {
      57         247 :     X509_free(x_);
      58             :   }
      59         332 : }
      60             : 
      61           2 : Certificate& Certificate::operator=(const Certificate& rhs)
      62             : {
      63           2 :   if (this != &rhs) {
      64           2 :     if (rhs.x_ && (0 < rhs.original_bytes_.length())) {
      65           2 :       deserialize(rhs.original_bytes_);
      66             :     }
      67             : 
      68             :   }
      69           2 :   return *this;
      70             : }
      71             : 
      72         220 : bool Certificate::load(DDS::Security::SecurityException& ex,
      73             :                        const std::string& uri,
      74             :                        const std::string& password)
      75             : {
      76             :   using namespace CommonUtilities;
      77             : 
      78         220 :   if (x_) {
      79           0 :     set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: document already loaded");
      80           0 :     return false;
      81             :   }
      82             : 
      83         220 :   URI uri_info(uri);
      84             : 
      85         220 :   switch (uri_info.scheme) {
      86         173 :   case URI::URI_FILE:
      87         173 :     load_cert_bytes(uri_info.everything_else);
      88         173 :     x_ = x509_from_pem(original_bytes_, password);
      89         173 :     break;
      90             : 
      91          47 :   case URI::URI_DATA:
      92          47 :     load_cert_data_bytes(uri_info.everything_else);
      93          47 :     x_ = x509_from_pem(original_bytes_, password);
      94          47 :     break;
      95             : 
      96           0 :   case URI::URI_PKCS11:
      97             :   case URI::URI_UNKNOWN:
      98             :   default:
      99           0 :     ACE_ERROR((LM_WARNING,
     100             :                "(%P|%t) SSL::Certificate::load: WARNING: Unsupported URI scheme\n"));
     101             : 
     102           0 :     break;
     103             :   }
     104             : 
     105         220 :   if (!loaded()) {
     106           1 :     std::stringstream msg;
     107             :     msg << "SSL::Certificate::load: WARNING: Failed to load document supplied "
     108           1 :       "with URI '"  << uri << "'";
     109           1 :     set_security_error(ex, -1, 0, msg.str().c_str());
     110           1 :     return false;
     111           1 :   }
     112             : 
     113         219 :   const int err = cache_dsign_algo();
     114         219 :   if (err) {
     115           0 :     set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: Failed to cache signature algorithm");
     116           0 :     return false;
     117             :   }
     118         219 :   return true;
     119         220 : }
     120             : 
     121          39 : int Certificate::validate(const Certificate& ca, unsigned long int flags) const
     122             : {
     123          39 :   if (!x_) {
     124           1 :     ACE_ERROR_RETURN((LM_WARNING,
     125             :                       ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING, a ")
     126             :                       ACE_TEXT("certificate must be loaded before it can be verified\n")), 1);
     127             :   }
     128             : 
     129          38 :   if (!ca.x_) {
     130           0 :     ACE_ERROR_RETURN((LM_WARNING,
     131             :                       ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING, passed-in ")
     132             :                       ACE_TEXT("CA has not loaded a certificate\n")), 1);
     133             :   }
     134             : 
     135          38 :   X509_STORE* const certs = X509_STORE_new();
     136          38 :   if (!certs) {
     137           0 :     OPENDDS_SSL_LOG_ERR("failed to create X509_STORE");
     138           0 :     return 1;
     139             :   }
     140             : 
     141          38 :   X509_STORE_add_cert(certs, ca.x_);
     142             : 
     143          38 :   X509_STORE_CTX* validation_ctx = X509_STORE_CTX_new();
     144          38 :   if (!validation_ctx) {
     145           0 :     X509_STORE_free(certs);
     146           0 :     return 1;
     147             :   }
     148             : 
     149          38 :   X509_STORE_CTX_init(validation_ctx, certs, x_, 0);
     150          38 :   X509_STORE_CTX_set_flags(validation_ctx, flags);
     151             : 
     152             :   int result =
     153          38 :     X509_verify_cert(validation_ctx) == 1
     154          38 :     ? X509_V_OK : 1; // X509_V_ERR_UNSPECIFIED is not provided by all OpenSSL versions
     155             : 
     156          38 :   if (result == 1) {
     157           1 :     const int err = X509_STORE_CTX_get_error(validation_ctx),
     158           1 :       depth = X509_STORE_CTX_get_error_depth(validation_ctx);
     159           1 :     ACE_ERROR((LM_WARNING,
     160             :                ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING '%C' occurred using cert at ")
     161             :                ACE_TEXT("depth '%i', validation failed.\n"),
     162             :                X509_verify_cert_error_string(err), depth));
     163           1 :     result = err;
     164             :   }
     165             : 
     166          38 :   X509_STORE_CTX_free(validation_ctx);
     167          38 :   X509_STORE_free(certs);
     168          38 :   return result;
     169             : }
     170             : 
     171             : class verify_implementation
     172             : {
     173             : public:
     174          15 :   explicit verify_implementation(EVP_PKEY* pkey)
     175          15 :     : public_key(pkey), md_ctx(0), pkey_ctx(0)
     176             :   {
     177          15 :   }
     178             : 
     179          15 :   ~verify_implementation() { EVP_MD_CTX_free(md_ctx); }
     180             : 
     181          15 :   int operator()(const DDS::OctetSeq& src,
     182             :                  const std::vector<const DDS::OctetSeq*>& expected_contents)
     183             :   {
     184          15 :     if (!public_key) return 1;
     185             : 
     186          15 :     int pk_id = 0;
     187          15 :     std::vector<const DDS::OctetSeq*>::const_iterator i, n;
     188             : 
     189          15 :     md_ctx = EVP_MD_CTX_new();
     190          15 :     if (!md_ctx) {
     191           0 :       OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
     192           0 :       return 1;
     193             :     }
     194             : 
     195          15 :     EVP_MD_CTX_init(md_ctx);
     196             : 
     197          15 :     if (1 != EVP_DigestVerifyInit(md_ctx, &pkey_ctx, EVP_sha256(), 0,
     198             :                                   public_key)) {
     199           0 :       OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyInit failed");
     200           0 :       return 1;
     201             :     }
     202             : 
     203             :     // Determine which signature type is being verified
     204          15 :     pk_id = EVP_PKEY_id(public_key);
     205             : 
     206          15 :     if (pk_id == EVP_PKEY_RSA) {
     207          14 :       if (1 !=
     208          14 :           EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING)) {
     209           0 :         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_padding failed");
     210           0 :         return 1;
     211             :       }
     212             : 
     213          14 :       if (1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256())) {
     214           0 :         OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_mgf1_md failed");
     215           0 :         return 1;
     216             :       }
     217             :     }
     218             : 
     219          15 :     n = expected_contents.end();
     220          33 :     for (i = expected_contents.begin(); i != n; ++i) {
     221          18 :       if ((*i)->length() > 0) {
     222          18 :         if (1 != EVP_DigestVerifyUpdate(md_ctx, (*i)->get_buffer(),
     223          18 :                                         (*i)->length())) {
     224           0 :           OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyUpdate failed");
     225           0 :           return 1;
     226             :         }
     227             :       }
     228             :     }
     229             : 
     230             : #ifdef OPENSSL_V_1_0
     231             :     // some versions of OpenSSL take a pointer to non-const
     232             :     unsigned char* buffer = const_cast<unsigned char*>(src.get_buffer());
     233             : #else
     234          15 :     const unsigned char* buffer = src.get_buffer();
     235             : #endif
     236          15 :     const int err = EVP_DigestVerifyFinal(md_ctx, buffer, src.length());
     237          15 :     if (0 == err) {
     238           1 :       return 1;  // Verification failed, but no error occurred
     239             : 
     240          14 :     } else if (1 != err) {
     241           0 :       OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyFinal failed");
     242           0 :       return 1;
     243             :     }
     244             : 
     245          14 :     return 0;
     246             :   }
     247             : 
     248             : private:
     249             :   EVP_PKEY* public_key;
     250             :   EVP_MD_CTX* md_ctx;
     251             :   EVP_PKEY_CTX* pkey_ctx;
     252             : };
     253             : 
     254          15 : int Certificate::verify_signature(
     255             :   const DDS::OctetSeq& src,
     256             :   const std::vector<const DDS::OctetSeq*>& expected_contents) const
     257             : {
     258             : #ifdef OPENSSL_V_1_0
     259             :   struct EVP_PKEY_Handle {
     260             :     EVP_PKEY* pkey_;
     261             :     explicit EVP_PKEY_Handle(EVP_PKEY* pkey) : pkey_(pkey) {}
     262             :     operator EVP_PKEY*() { return pkey_; }
     263             :     ~EVP_PKEY_Handle() { EVP_PKEY_free(pkey_); }
     264             :   } pkey(X509_get_pubkey(x_));
     265             : #else
     266          15 :   EVP_PKEY* pkey = X509_get0_pubkey(x_);
     267             : #endif
     268          15 :   verify_implementation verify(pkey);
     269          30 :   return verify(src, expected_contents);
     270          15 : }
     271             : 
     272          55 : int Certificate::subject_name_to_str(std::string& dst,
     273             :                                      unsigned long flags) const
     274             : {
     275          55 :   int result = 1;
     276             : 
     277          55 :   dst.clear();
     278             : 
     279          55 :   if (x_) {
     280             :     /* Do not free name! */
     281          55 :     X509_NAME* name = X509_get_subject_name(x_);
     282          55 :     if (name) {
     283          55 :       BIO* buffer = BIO_new(BIO_s_mem());
     284          55 :       if (buffer) {
     285          55 :         int len = X509_NAME_print_ex(buffer, name, 0, flags);
     286          55 :         if (len > 0) {
     287          55 :           std::vector<char> tmp(len +
     288          55 :                                 1);  // BIO_gets will add null hence +1
     289          55 :           len = BIO_gets(buffer, &tmp[0], len + 1);
     290          55 :           if (len > 0) {
     291         110 :             std::copy(
     292             :                       tmp.begin(),
     293          55 :                       tmp.end() -
     294             :                       1,  // But... string inserts a null so it's not needed
     295             :                       std::back_inserter(dst));
     296          55 :             result = 0;
     297             : 
     298             :           } else {
     299           0 :             OPENDDS_SSL_LOG_ERR("failed to write BIO to string");
     300             :           }
     301             : 
     302          55 :         } else {
     303           0 :           OPENDDS_SSL_LOG_ERR("failed to read X509_NAME into BIO buffer");
     304             :         }
     305             : 
     306          55 :         BIO_free(buffer);
     307             :       }
     308             :     }
     309             :   }
     310             : 
     311          55 :   return result;
     312             : }
     313             : 
     314          60 : int Certificate::subject_name_digest(std::vector<CORBA::Octet>& dst) const
     315             : {
     316          60 :   dst.clear();
     317             : 
     318          60 :   if (!x_) return 1;
     319             : 
     320             :   /* Do not free name! */
     321          60 :   X509_NAME* name = X509_get_subject_name(x_);
     322          60 :   if (0 == name) {
     323           0 :     OPENDDS_SSL_LOG_ERR("X509_get_subject_name failed");
     324           0 :     return 1;
     325             :   }
     326             : 
     327          60 :   std::vector<CORBA::Octet> tmp(EVP_MAX_MD_SIZE);
     328             : 
     329          60 :   unsigned int len = 0;
     330          60 :   if (1 != X509_NAME_digest(name, EVP_sha256(), &tmp[0], &len)) {
     331           0 :     OPENDDS_SSL_LOG_ERR("X509_NAME_digest failed");
     332           0 :     return 1;
     333             :   }
     334             : 
     335          60 :   dst.insert(dst.begin(), tmp.begin(), tmp.begin() + len);
     336             : 
     337          60 :   return 0;
     338          60 : }
     339             : 
     340          42 : const char* Certificate::keypair_algo() const
     341             : {
     342             :   // This should probably be pulling the information directly from
     343             :   // the certificate.
     344          42 :   if (std::string("RSASSA-PSS-SHA256") == dsign_algo_) {
     345          42 :     return "RSA-2048";
     346             : 
     347           0 :   } else if (std::string("ECDSA-SHA256") == dsign_algo_) {
     348           0 :     return "EC-prime256v1";
     349             : 
     350             :   } else {
     351           0 :     return "UNKNOWN";
     352             :   }
     353             : }
     354             : 
     355             : struct cache_dsign_algo_impl
     356             : {
     357             : #ifndef OPENSSL_V_3_0
     358             :   cache_dsign_algo_impl() : pkey_(0), rsa_(0), ec_(0) {}
     359             :   ~cache_dsign_algo_impl()
     360             :   {
     361             :     EVP_PKEY_free(pkey_);
     362             :     RSA_free(rsa_);
     363             :     EC_KEY_free(ec_);
     364             :   }
     365             : #else
     366         247 :   cache_dsign_algo_impl() : pkey_(0) {}
     367         247 :   ~cache_dsign_algo_impl()
     368             :   {
     369         247 :     EVP_PKEY_free(pkey_);
     370         247 :   }
     371             : #endif
     372             : 
     373         247 :   int operator() (X509* cert, std::string& dst)
     374             :   {
     375         247 :     if (!cert) {
     376           0 :       ACE_ERROR((LM_WARNING,
     377             :                  "(%P|%t) SSL::Certificate::cache_dsign_algo: WARNING, failed to "
     378             :                  "get pubkey from X509 cert\n"));
     379           0 :       return 1;
     380             :     }
     381             : 
     382         247 :     pkey_ = X509_get_pubkey(cert);
     383         247 :     if (!pkey_) {
     384           0 :       OPENDDS_SSL_LOG_ERR("cache_dsign_algo_impl::operator(): x509_get_pubkey failed");
     385           0 :       return 1;
     386             :     }
     387             : 
     388             : #ifndef OPENSSL_V_3_0
     389             :     rsa_ = EVP_PKEY_get1_RSA(pkey_);
     390             :     if (rsa_) {
     391             :       dst = "RSASSA-PSS-SHA256";
     392             :       return 0;
     393             :     }
     394             : 
     395             :     ec_ = EVP_PKEY_get1_EC_KEY(pkey_);
     396             :     if (ec_) {
     397             :       dst = "ECDSA-SHA256";
     398             :       return 0;
     399             :     }
     400             : #else
     401         247 :     const int ptype = EVP_PKEY_id (pkey_);
     402         247 :     if (ptype == EVP_PKEY_RSA || ptype == EVP_PKEY_RSA_PSS) {
     403         224 :       dst = "RSASSA-PSS-SHA256";
     404         224 :       return 0;
     405          23 :     } else if (ptype == EVP_PKEY_EC) {
     406          23 :       dst = "ECDSA-SHA256";
     407          23 :       return 0;
     408             :     }
     409             : #endif
     410             : 
     411           0 :     ACE_ERROR((LM_WARNING,
     412             :                "(%P|%t) SSL::Certificate::cache_dsign_algo: WARNING, only RSASSA-PSS-SHA256 or "
     413             :                "ECDSA-SHA256 are currently supported signature/verification algorithms\n"));
     414             : 
     415           0 :     return 1;
     416             :   }
     417             : 
     418             : private:
     419             :   EVP_PKEY* pkey_;
     420             : #ifndef OPENSSL_V_3_0
     421             :   RSA* rsa_;
     422             :   EC_KEY* ec_;
     423             : #endif
     424             : };
     425             : 
     426         247 : int Certificate::cache_dsign_algo()
     427             : {
     428         247 :   return cache_dsign_algo_impl()(x_, dsign_algo_);
     429             : }
     430             : 
     431         173 : void Certificate::load_cert_bytes(const std::string& path)
     432             : {
     433             : #ifdef ACE_ANDROID
     434             :   CORBA::Octet *buffer;
     435             : 
     436             :   char b[1024];
     437             :   FILE* fp = ACE_OS::fopen(path.c_str(), "rb");
     438             : 
     439             :   int n;
     440             :   int i = 0;
     441             :   while (!feof(fp)) {
     442             :     n = ACE_OS::fread(&b, 1, 1024, fp);
     443             :     i += n;
     444             : 
     445             :     original_bytes_.length(i + 1); // +1 for null byte at end of cert
     446             :     buffer = original_bytes_.get_buffer();
     447             :     ACE_OS::memcpy(buffer + i - n, b, n);
     448             :   }
     449             : 
     450             :   ACE_OS::fclose(fp);
     451             : 
     452             :   // To appease the other DDS security implementations which
     453             :   // append a null byte at the end of the cert.
     454             :   buffer[i + 1] = 0u;
     455             : 
     456             : #else
     457         173 :   std::ifstream in(path.c_str(), std::ios::binary);
     458             : 
     459         173 :   if (!in) {
     460           0 :     ACE_ERROR((LM_WARNING,
     461             :                "(%P|%t) Certificate::load_cert_bytes:"
     462             :                "WARNING: Failed to load file '%C'; '%m'\n",
     463             :                path.c_str()));
     464           0 :     return;
     465             :   }
     466             : 
     467         173 :   const std::ifstream::pos_type begin = in.tellg();
     468         173 :   in.seekg(0, std::ios::end);
     469         173 :   const std::ifstream::pos_type end = in.tellg();
     470         173 :   in.seekg(0, std::ios::beg);
     471             : 
     472         173 :   original_bytes_.length(static_cast<CORBA::ULong>(end - begin + 1));
     473         173 :   in.read(reinterpret_cast<char*>(original_bytes_.get_buffer()), end - begin);
     474             : 
     475         173 :   if (!in) {
     476           0 :     ACE_ERROR((LM_WARNING,
     477             :                "(%P|%t) Certificate::load_cert_bytes:"
     478             :                "WARNING: Failed to load file '%C'; '%m'\n",
     479             :                path.c_str()));
     480           0 :     return;
     481             :   }
     482             : 
     483             :   // To appease the other DDS security implementations which
     484             :   // append a null byte at the end of the cert.
     485         173 :   original_bytes_[original_bytes_.length() - 1] = 0u;
     486             : #endif
     487         173 : }
     488             : 
     489          47 : void Certificate::load_cert_data_bytes(const std::string& data)
     490             : {
     491             :   // Start at position 1 because path contains a comma in element 0
     492             :   // and that comma is not included in the cert string
     493             :   // copy the full length to get the terminating null
     494          47 :   original_bytes_.length(static_cast<unsigned int>(data.size()));
     495          47 :   std::memcpy(original_bytes_.get_buffer(), data.c_str() + 1, data.size());
     496          47 : }
     497             : 
     498           0 : X509* Certificate::x509_from_pem(const std::string& path,
     499             :                                  const std::string& password)
     500             : {
     501           0 :   X509* result = NULL;
     502             : 
     503           0 :   BIO* filebuf = BIO_new_file(path.c_str(), "r");
     504           0 :   if (filebuf) {
     505           0 :     if (!password.empty()) {
     506             :       result =
     507           0 :         PEM_read_bio_X509_AUX(filebuf, 0, 0, (void*)password.c_str());
     508           0 :       if (!result) {
     509           0 :         OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
     510             :       }
     511             : 
     512             :     } else {
     513           0 :       result = PEM_read_bio_X509_AUX(filebuf, 0, 0, 0);
     514           0 :       if (!result) {
     515           0 :         OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
     516             :       }
     517             :     }
     518             : 
     519           0 :     BIO_free(filebuf);
     520             : 
     521             :   } else {
     522           0 :     std::stringstream errmsg;
     523           0 :     errmsg << "failed to read file '" << path << "' using BIO_new_file";
     524           0 :     OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
     525           0 :   }
     526             : 
     527           0 :   return result;
     528             : }
     529             : 
     530         220 : X509* Certificate::x509_from_pem(const DDS::OctetSeq& bytes,
     531             :                                  const std::string& password)
     532             : {
     533         220 :   X509* result = 0;
     534             : 
     535         220 :   BIO* filebuf = BIO_new(BIO_s_mem());
     536             :   do {
     537         220 :     if (filebuf) {
     538         220 :       if (0 >= BIO_write(filebuf, bytes.get_buffer(), bytes.length())) {
     539           0 :         OPENDDS_SSL_LOG_ERR("BIO_write failed");
     540           0 :         break;
     541             :       }
     542         220 :       if (!password.empty()) {
     543           0 :         result = PEM_read_bio_X509_AUX(filebuf, 0, 0,
     544           0 :                                        (void*)password.c_str());
     545           0 :         if (!result) {
     546           0 :           OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
     547           0 :           break;
     548             :         }
     549             : 
     550             :       } else {
     551         220 :         result = PEM_read_bio_X509_AUX(filebuf, 0, 0, 0);
     552         220 :         if (!result) {
     553           2 :           OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
     554           1 :           break;
     555             :         }
     556             :       }
     557             : 
     558             :     } else {
     559           0 :       std::stringstream errmsg;
     560           0 :       errmsg << "BIO_new failed";
     561           0 :       OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
     562           0 :       break;
     563           0 :     }
     564             : 
     565             :   } while (0);
     566             : 
     567         220 :   BIO_free(filebuf);
     568             : 
     569         220 :   return result;
     570             : }
     571             : 
     572           2 : int Certificate::serialize(DDS::OctetSeq& dst) const
     573             : {
     574           2 :   dst = original_bytes_;
     575             : 
     576           2 :   if (dst.length() == original_bytes_.length()) {
     577           2 :     return 0;
     578             :   }
     579             : 
     580           0 :   return 1;
     581             : }
     582             : 
     583             : struct deserialize_impl
     584             : {
     585          28 :   explicit deserialize_impl(const DDS::OctetSeq& src)
     586          28 :     : src_(src), buffer_(BIO_new(BIO_s_mem()))
     587          28 :   {}
     588             : 
     589          28 :   ~deserialize_impl()
     590             :   {
     591          28 :     BIO_free(buffer_);
     592          28 :   }
     593             : 
     594          28 :   int operator() (X509*& dst)
     595             :   {
     596          28 :     if (dst) {
     597           0 :       ACE_ERROR((LM_WARNING,
     598             :                  "(%P|%t) SSL::Certificate::deserialize: WARNING, an X509 certificate "
     599             :                  "has already been loaded\n"));
     600           0 :       return 1;
     601             :     }
     602             : 
     603          28 :     if (0 == src_.length()) {
     604           0 :       ACE_ERROR((LM_WARNING,
     605             :                  "(%P|%t) SSL::Certificate::deserialize: WARNING, source OctetSeq contains no data"));
     606           0 :       return 1;
     607             :     }
     608             : 
     609          28 :     if (!buffer_) {
     610           0 :       OPENDDS_SSL_LOG_ERR("failed to allocate buffer with BIO_new");
     611           0 :       return 1;
     612             :     }
     613             : 
     614          28 :     const int len = BIO_write(buffer_, src_.get_buffer(), src_.length());
     615          28 :     if (len <= 0) {
     616           0 :       OPENDDS_SSL_LOG_ERR("failed to write OctetSeq to BIO");
     617           0 :       return 1;
     618             :     }
     619             : 
     620          28 :     dst = PEM_read_bio_X509_AUX(buffer_, 0, 0, 0);
     621          28 :     if (! dst) {
     622           0 :       OPENDDS_SSL_LOG_ERR("failed to read X509 from BIO");
     623           0 :       return 1;
     624             :     }
     625             : 
     626          28 :     return 0;
     627             :   }
     628             : 
     629             : private:
     630             :   const DDS::OctetSeq& src_;
     631             :   BIO* buffer_;
     632             : };
     633             : 
     634          28 : int Certificate::deserialize(const DDS::OctetSeq& src)
     635             : {
     636          28 :   int err = deserialize_impl(src)(x_) || cache_dsign_algo();
     637          28 :   if (!err) {
     638          28 :     original_bytes_ = src;
     639             :   }
     640             : 
     641          28 :   return err;
     642             : }
     643             : 
     644           0 : std::ostream& operator<<(std::ostream& lhs, const Certificate& rhs)
     645             : {
     646           0 :   if (rhs.x_) {
     647             :     lhs << "Certificate: { is_ca? '"
     648           0 :         << (X509_check_ca(rhs.x_) ? "yes" : "no") << "'; }";
     649             : 
     650             :   } else {
     651           0 :     lhs << "NULL";
     652             :   }
     653           0 :   return lhs;
     654             : }
     655             : 
     656           8 : bool operator==(const Certificate& lhs, const Certificate& rhs)
     657             : {
     658           8 :   if (lhs.x_ && rhs.x_) {
     659          16 :     return (0 == X509_cmp(lhs.x_, rhs.x_)) &&
     660          16 :       (lhs.original_bytes_ == rhs.original_bytes_);
     661             :   }
     662           0 :   return (lhs.x_ == rhs.x_) &&
     663           0 :     (lhs.original_bytes_ == rhs.original_bytes_);
     664             : }
     665             : 
     666             : }  // namespace SSL
     667             : }  // namespace Security
     668             : }  // namespace OpenDDS
     669             : 
     670             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16