OpenDDS  Snapshot(2023/04/28-20:55)
Public Types | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | Friends | List of all members
OpenDDS::Security::SSL::Certificate Class Reference

#include <Certificate.h>

Collaboration diagram for OpenDDS::Security::SSL::Certificate:
Collaboration graph
[legend]

Public Types

typedef DCPS::unique_ptr< Certificateunique_ptr
 

Public Member Functions

 Certificate (const std::string &uri, const std::string &password="")
 
 Certificate (const DDS::OctetSeq &src)
 
 Certificate (const Certificate &other)
 
 Certificate ()
 
virtual ~Certificate ()
 
Certificateoperator= (const Certificate &rhs)
 
bool load (DDS::Security::SecurityException &ex, const std::string &uri, const std::string &password="")
 
int validate (const Certificate &ca, unsigned long int flags=0u) const
 
int verify_signature (const DDS::OctetSeq &src, const std::vector< const DDS::OctetSeq *> &expected_contents) const
 
int subject_name_to_str (std::string &dst, unsigned long flags=XN_FLAG_ONELINE) const
 
int subject_name_digest (std::vector< CORBA::Octet > &dst) const
 
int serialize (DDS::OctetSeq &dst) const
 
int deserialize (const DDS::OctetSeq &src)
 
const DDS::OctetSeqoriginal_bytes () const
 
const char * dsign_algo () const
 
const char * keypair_algo () const
 
X509x509 () const
 

Private Member Functions

bool loaded ()
 
int cache_dsign_algo ()
 
void load_cert_bytes (const std::string &path)
 
void load_cert_data_bytes (const std::string &data)
 

Static Private Member Functions

static X509x509_from_pem (const std::string &path, const std::string &password="")
 
static X509x509_from_pem (const DDS::OctetSeq &bytes, const std::string &password="")
 

Private Attributes

X509x_
 
DDS::OctetSeq original_bytes_
 
std::string dsign_algo_
 

Friends

class verify_signature_impl
 
OpenDDS_Security_Export std::ostreamoperator<< (std::ostream &, const Certificate &)
 
OpenDDS_Security_Export bool operator== (const Certificate &lhs, const Certificate &rhs)
 

Detailed Description

Definition at line 29 of file Certificate.h.

Member Typedef Documentation

◆ unique_ptr

Definition at line 33 of file Certificate.h.

Constructor & Destructor Documentation

◆ Certificate() [1/4]

OpenDDS::Security::SSL::Certificate::Certificate ( const std::string &  uri,
const std::string &  password = "" 
)
explicit

Definition at line 25 of file Certificate.cpp.

References ACE_ERROR, LM_WARNING, load(), and DDS::Security::SecurityException::message.

27  : x_(0), original_bytes_(), dsign_algo_("")
28 {
30  if (! load(ex, uri, password)) {
31  ACE_ERROR((LM_WARNING, "(%P|%t) %C\n", ex.message.in()));
32  }
33 }
#define ACE_ERROR(X)
bool load(DDS::Security::SecurityException &ex, const std::string &uri, const std::string &password="")
Definition: Certificate.cpp:72

◆ Certificate() [2/4]

OpenDDS::Security::SSL::Certificate::Certificate ( const DDS::OctetSeq src)
explicit

Definition at line 35 of file Certificate.cpp.

References deserialize().

36  : x_(0), original_bytes_(), dsign_algo_("")
37 {
38  deserialize(src);
39 }
int deserialize(const DDS::OctetSeq &src)

◆ Certificate() [3/4]

OpenDDS::Security::SSL::Certificate::Certificate ( const Certificate other)

Definition at line 46 of file Certificate.cpp.

References deserialize(), and original_bytes_.

47  : x_(0), original_bytes_(), dsign_algo_("")
48 {
49  if (0 < other.original_bytes_.length()) {
50  deserialize(other.original_bytes_);
51  }
52 }
int deserialize(const DDS::OctetSeq &src)

◆ Certificate() [4/4]

OpenDDS::Security::SSL::Certificate::Certificate ( )

Definition at line 41 of file Certificate.cpp.

◆ ~Certificate()

OpenDDS::Security::SSL::Certificate::~Certificate ( )
virtual

Definition at line 54 of file Certificate.cpp.

References x_.

55 {
56  if (x_) {
57  X509_free(x_);
58  }
59 }

Member Function Documentation

◆ cache_dsign_algo()

int OpenDDS::Security::SSL::Certificate::cache_dsign_algo ( )
private
Returns
int 0 on success; 1 on failure.

Definition at line 426 of file Certificate.cpp.

References dsign_algo_, and x_.

Referenced by deserialize(), and load().

427 {
428  return cache_dsign_algo_impl()(x_, dsign_algo_);
429 }

◆ deserialize()

int OpenDDS::Security::SSL::Certificate::deserialize ( const DDS::OctetSeq src)
Returns
int 0 on success; 1 on failure.

Definition at line 634 of file Certificate.cpp.

References cache_dsign_algo(), original_bytes_, and x_.

Referenced by Certificate(), and operator=().

635 {
636  int err = deserialize_impl(src)(x_) || cache_dsign_algo();
637  if (!err) {
638  original_bytes_ = src;
639  }
640 
641  return err;
642 }

◆ dsign_algo()

const char* OpenDDS::Security::SSL::Certificate::dsign_algo ( ) const
inline

◆ keypair_algo()

const char * OpenDDS::Security::SSL::Certificate::keypair_algo ( ) const

Definition at line 340 of file Certificate.cpp.

References dsign_algo_.

Referenced by OpenDDS::Security::AuthenticationBuiltInImpl::get_identity_token().

341 {
342  // This should probably be pulling the information directly from
343  // the certificate.
344  if (std::string("RSASSA-PSS-SHA256") == dsign_algo_) {
345  return "RSA-2048";
346 
347  } else if (std::string("ECDSA-SHA256") == dsign_algo_) {
348  return "EC-prime256v1";
349 
350  } else {
351  return "UNKNOWN";
352  }
353 }

◆ load()

bool OpenDDS::Security::SSL::Certificate::load ( DDS::Security::SecurityException ex,
const std::string &  uri,
const std::string &  password = "" 
)

Definition at line 72 of file Certificate.cpp.

References ACE_ERROR, cache_dsign_algo(), OpenDDS::Security::CommonUtilities::URI::everything_else, LM_WARNING, load_cert_bytes(), load_cert_data_bytes(), loaded(), original_bytes_, OpenDDS::Security::CommonUtilities::URI::scheme, OpenDDS::Security::CommonUtilities::set_security_error(), OpenDDS::Security::CommonUtilities::URI::URI_DATA, OpenDDS::Security::CommonUtilities::URI::URI_FILE, OpenDDS::Security::CommonUtilities::URI::URI_PKCS11, OpenDDS::Security::CommonUtilities::URI::URI_UNKNOWN, x509_from_pem(), and x_.

Referenced by Certificate().

75 {
76  using namespace CommonUtilities;
77 
78  if (x_) {
79  set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: document already loaded");
80  return false;
81  }
82 
83  URI uri_info(uri);
84 
85  switch (uri_info.scheme) {
86  case URI::URI_FILE:
87  load_cert_bytes(uri_info.everything_else);
88  x_ = x509_from_pem(original_bytes_, password);
89  break;
90 
91  case URI::URI_DATA:
92  load_cert_data_bytes(uri_info.everything_else);
93  x_ = x509_from_pem(original_bytes_, password);
94  break;
95 
96  case URI::URI_PKCS11:
97  case URI::URI_UNKNOWN:
98  default:
99  ACE_ERROR((LM_WARNING,
100  "(%P|%t) SSL::Certificate::load: WARNING: Unsupported URI scheme\n"));
101 
102  break;
103  }
104 
105  if (!loaded()) {
106  std::stringstream msg;
107  msg << "SSL::Certificate::load: WARNING: Failed to load document supplied "
108  "with URI '" << uri << "'";
109  set_security_error(ex, -1, 0, msg.str().c_str());
110  return false;
111  }
112 
113  const int err = cache_dsign_algo();
114  if (err) {
115  set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: Failed to cache signature algorithm");
116  return false;
117  }
118  return true;
119 }
#define ACE_ERROR(X)
void load_cert_bytes(const std::string &path)
void load_cert_data_bytes(const std::string &data)
static X509 * x509_from_pem(const std::string &path, const std::string &password="")
bool set_security_error(DDS::Security::SecurityException &ex, int code, int minor_code, const char *message)

◆ load_cert_bytes()

void OpenDDS::Security::SSL::Certificate::load_cert_bytes ( const std::string &  path)
private

Definition at line 431 of file Certificate.cpp.

References ACE_ERROR, ACE_OS::fclose(), ACE_OS::fopen(), ACE_OS::fread(), LM_WARNING, ACE_OS::memcpy(), and original_bytes_.

Referenced by load().

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  std::ifstream in(path.c_str(), std::ios::binary);
458 
459  if (!in) {
460  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  return;
465  }
466 
467  const std::ifstream::pos_type begin = in.tellg();
468  in.seekg(0, std::ios::end);
469  const std::ifstream::pos_type end = in.tellg();
470  in.seekg(0, std::ios::beg);
471 
472  original_bytes_.length(static_cast<CORBA::ULong>(end - begin + 1));
473  in.read(reinterpret_cast<char*>(original_bytes_.get_buffer()), end - begin);
474 
475  if (!in) {
476  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  return;
481  }
482 
483  // To appease the other DDS security implementations which
484  // append a null byte at the end of the cert.
485  original_bytes_[original_bytes_.length() - 1] = 0u;
486 #endif
487 }
int fclose(FILE *fp)
#define ACE_ERROR(X)
void * memcpy(void *t, const void *s, size_t len)
FILE * fopen(const char *filename, const char *mode)
size_t fread(void *ptr, size_t size, size_t nelems, FILE *fp)
ACE_CDR::Octet Octet

◆ load_cert_data_bytes()

void OpenDDS::Security::SSL::Certificate::load_cert_data_bytes ( const std::string &  data)
private

Definition at line 489 of file Certificate.cpp.

References original_bytes_.

Referenced by load().

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  original_bytes_.length(static_cast<unsigned int>(data.size()));
495  std::memcpy(original_bytes_.get_buffer(), data.c_str() + 1, data.size());
496 }

◆ loaded()

bool OpenDDS::Security::SSL::Certificate::loaded ( )
inlineprivate

Definition at line 100 of file Certificate.h.

Referenced by load().

101  {
102  return (x_ != NULL) &&
103  (0 < original_bytes_.length());
104  }

◆ operator=()

Certificate & OpenDDS::Security::SSL::Certificate::operator= ( const Certificate rhs)

Definition at line 61 of file Certificate.cpp.

References deserialize(), original_bytes_, and x_.

62 {
63  if (this != &rhs) {
64  if (rhs.x_ && (0 < rhs.original_bytes_.length())) {
65  deserialize(rhs.original_bytes_);
66  }
67 
68  }
69  return *this;
70 }
int deserialize(const DDS::OctetSeq &src)

◆ original_bytes()

const DDS::OctetSeq& OpenDDS::Security::SSL::Certificate::original_bytes ( ) const
inline

◆ serialize()

int OpenDDS::Security::SSL::Certificate::serialize ( DDS::OctetSeq dst) const
Returns
int 0 on success; 1 on failure.

Definition at line 572 of file Certificate.cpp.

References original_bytes_.

573 {
574  dst = original_bytes_;
575 
576  if (dst.length() == original_bytes_.length()) {
577  return 0;
578  }
579 
580  return 1;
581 }

◆ subject_name_digest()

int OpenDDS::Security::SSL::Certificate::subject_name_digest ( std::vector< CORBA::Octet > &  dst) const
Returns
int 0 on success; 1 on failure.

Definition at line 314 of file Certificate.cpp.

References name, OPENDDS_SSL_LOG_ERR, and x_.

Referenced by OpenDDS::Security::SSL::make_adjusted_guid().

315 {
316  dst.clear();
317 
318  if (!x_) return 1;
319 
320  /* Do not free name! */
321  X509_NAME* name = X509_get_subject_name(x_);
322  if (0 == name) {
323  OPENDDS_SSL_LOG_ERR("X509_get_subject_name failed");
324  return 1;
325  }
326 
327  std::vector<CORBA::Octet> tmp(EVP_MAX_MD_SIZE);
328 
329  unsigned int len = 0;
330  if (1 != X509_NAME_digest(name, EVP_sha256(), &tmp[0], &len)) {
331  OPENDDS_SSL_LOG_ERR("X509_NAME_digest failed");
332  return 1;
333  }
334 
335  dst.insert(dst.begin(), tmp.begin(), tmp.begin() + len);
336 
337  return 0;
338 }
const char *const name
Definition: debug.cpp:60
#define OPENDDS_SSL_LOG_ERR(MSG)
Definition: Err.h:12

◆ subject_name_to_str()

int OpenDDS::Security::SSL::Certificate::subject_name_to_str ( std::string &  dst,
unsigned long  flags = XN_FLAG_ONELINE 
) const
Returns
int 0 on success; 1 on failure.

Definition at line 272 of file Certificate.cpp.

References OpenDDS::DCPS::back_inserter(), OpenDDS::XTypes::copy(), name, OPENDDS_SSL_LOG_ERR, and x_.

Referenced by OpenDDS::Security::AuthenticationBuiltInImpl::get_identity_token(), and OpenDDS::Security::AccessControlBuiltInImpl::validate_remote_permissions().

274 {
275  int result = 1;
276 
277  dst.clear();
278 
279  if (x_) {
280  /* Do not free name! */
281  X509_NAME* name = X509_get_subject_name(x_);
282  if (name) {
283  BIO* buffer = BIO_new(BIO_s_mem());
284  if (buffer) {
285  int len = X509_NAME_print_ex(buffer, name, 0, flags);
286  if (len > 0) {
287  std::vector<char> tmp(len +
288  1); // BIO_gets will add null hence +1
289  len = BIO_gets(buffer, &tmp[0], len + 1);
290  if (len > 0) {
291  std::copy(
292  tmp.begin(),
293  tmp.end() -
294  1, // But... string inserts a null so it's not needed
295  std::back_inserter(dst));
296  result = 0;
297 
298  } else {
299  OPENDDS_SSL_LOG_ERR("failed to write BIO to string");
300  }
301 
302  } else {
303  OPENDDS_SSL_LOG_ERR("failed to read X509_NAME into BIO buffer");
304  }
305 
306  BIO_free(buffer);
307  }
308  }
309  }
310 
311  return result;
312 }
SequenceBackInsertIterator< Sequence > back_inserter(Sequence &seq)
const char *const name
Definition: debug.cpp:60
DDS::ReturnCode_t copy(DDS::DynamicData_ptr dest, DDS::DynamicData_ptr src)
#define OPENDDS_SSL_LOG_ERR(MSG)
Definition: Err.h:12

◆ validate()

int OpenDDS::Security::SSL::Certificate::validate ( const Certificate ca,
unsigned long int  flags = 0u 
) const
Returns
int 0 on success; 1 on failure.

Definition at line 121 of file Certificate.cpp.

References ACE_ERROR, ACE_ERROR_RETURN, ACE_TEXT(), LM_WARNING, OPENDDS_SSL_LOG_ERR, and x_.

122 {
123  if (!x_) {
124  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  if (!ca.x_) {
130  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  X509_STORE* const certs = X509_STORE_new();
136  if (!certs) {
137  OPENDDS_SSL_LOG_ERR("failed to create X509_STORE");
138  return 1;
139  }
140 
141  X509_STORE_add_cert(certs, ca.x_);
142 
143  X509_STORE_CTX* validation_ctx = X509_STORE_CTX_new();
144  if (!validation_ctx) {
145  X509_STORE_free(certs);
146  return 1;
147  }
148 
149  X509_STORE_CTX_init(validation_ctx, certs, x_, 0);
150  X509_STORE_CTX_set_flags(validation_ctx, flags);
151 
152  int result =
153  X509_verify_cert(validation_ctx) == 1
154  ? X509_V_OK : 1; // X509_V_ERR_UNSPECIFIED is not provided by all OpenSSL versions
155 
156  if (result == 1) {
157  const int err = X509_STORE_CTX_get_error(validation_ctx),
158  depth = X509_STORE_CTX_get_error_depth(validation_ctx);
159  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  result = err;
164  }
165 
166  X509_STORE_CTX_free(validation_ctx);
167  X509_STORE_free(certs);
168  return result;
169 }
#define ACE_ERROR(X)
ACE_TEXT("TCP_Factory")
#define ACE_ERROR_RETURN(X, Y)
#define OPENDDS_SSL_LOG_ERR(MSG)
Definition: Err.h:12

◆ verify_signature()

int OpenDDS::Security::SSL::Certificate::verify_signature ( const DDS::OctetSeq src,
const std::vector< const DDS::OctetSeq *> &  expected_contents 
) const
Returns
int 0 on success; 1 on failure.

Definition at line 254 of file Certificate.cpp.

References pkey_, and x_.

Referenced by OpenDDS::Security::SSL::verify_serialized().

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  EVP_PKEY* pkey = X509_get0_pubkey(x_);
267 #endif
268  verify_implementation verify(pkey);
269  return verify(src, expected_contents);
270 }
EVP_PKEY * pkey_
struct evp_pkey_st EVP_PKEY

◆ x509()

X509* OpenDDS::Security::SSL::Certificate::x509 ( ) const
inline

◆ x509_from_pem() [1/2]

X509 * OpenDDS::Security::SSL::Certificate::x509_from_pem ( const std::string &  path,
const std::string &  password = "" 
)
staticprivate

Definition at line 498 of file Certificate.cpp.

References OPENDDS_SSL_LOG_ERR.

Referenced by load().

500 {
501  X509* result = NULL;
502 
503  BIO* filebuf = BIO_new_file(path.c_str(), "r");
504  if (filebuf) {
505  if (!password.empty()) {
506  result =
507  PEM_read_bio_X509_AUX(filebuf, 0, 0, (void*)password.c_str());
508  if (!result) {
509  OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
510  }
511 
512  } else {
513  result = PEM_read_bio_X509_AUX(filebuf, 0, 0, 0);
514  if (!result) {
515  OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
516  }
517  }
518 
519  BIO_free(filebuf);
520 
521  } else {
522  std::stringstream errmsg;
523  errmsg << "failed to read file '" << path << "' using BIO_new_file";
524  OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
525  }
526 
527  return result;
528 }
struct x509_st X509
#define OPENDDS_SSL_LOG_ERR(MSG)
Definition: Err.h:12

◆ x509_from_pem() [2/2]

X509 * OpenDDS::Security::SSL::Certificate::x509_from_pem ( const DDS::OctetSeq bytes,
const std::string &  password = "" 
)
staticprivate

Definition at line 530 of file Certificate.cpp.

References OPENDDS_SSL_LOG_ERR.

532 {
533  X509* result = 0;
534 
535  BIO* filebuf = BIO_new(BIO_s_mem());
536  do {
537  if (filebuf) {
538  if (0 >= BIO_write(filebuf, bytes.get_buffer(), bytes.length())) {
539  OPENDDS_SSL_LOG_ERR("BIO_write failed");
540  break;
541  }
542  if (!password.empty()) {
543  result = PEM_read_bio_X509_AUX(filebuf, 0, 0,
544  (void*)password.c_str());
545  if (!result) {
546  OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
547  break;
548  }
549 
550  } else {
551  result = PEM_read_bio_X509_AUX(filebuf, 0, 0, 0);
552  if (!result) {
553  OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
554  break;
555  }
556  }
557 
558  } else {
559  std::stringstream errmsg;
560  errmsg << "BIO_new failed";
561  OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
562  break;
563  }
564 
565  } while (0);
566 
567  BIO_free(filebuf);
568 
569  return result;
570 }
struct x509_st X509
#define OPENDDS_SSL_LOG_ERR(MSG)
Definition: Err.h:12

Friends And Related Function Documentation

◆ operator<<

OpenDDS_Security_Export std::ostream& operator<< ( std::ostream ,
const Certificate  
)
friend

Definition at line 644 of file Certificate.cpp.

645 {
646  if (rhs.x_) {
647  lhs << "Certificate: { is_ca? '"
648  << (X509_check_ca(rhs.x_) ? "yes" : "no") << "'; }";
649 
650  } else {
651  lhs << "NULL";
652  }
653  return lhs;
654 }

◆ operator==

OpenDDS_Security_Export bool operator== ( const Certificate lhs,
const Certificate rhs 
)
friend

Definition at line 656 of file Certificate.cpp.

657 {
658  if (lhs.x_ && rhs.x_) {
659  return (0 == X509_cmp(lhs.x_, rhs.x_)) &&
660  (lhs.original_bytes_ == rhs.original_bytes_);
661  }
662  return (lhs.x_ == rhs.x_) &&
663  (lhs.original_bytes_ == rhs.original_bytes_);
664 }

◆ verify_signature_impl

friend class verify_signature_impl
friend

Definition at line 31 of file Certificate.h.

Member Data Documentation

◆ dsign_algo_

std::string OpenDDS::Security::SSL::Certificate::dsign_algo_
private

Definition at line 123 of file Certificate.h.

Referenced by cache_dsign_algo(), and keypair_algo().

◆ original_bytes_

DDS::OctetSeq OpenDDS::Security::SSL::Certificate::original_bytes_
private

◆ x_

X509* OpenDDS::Security::SSL::Certificate::x_
private

The documentation for this class was generated from the following files: