00001
00002
00003
00004
00005
00006 #include "Certificate.h"
00007 #include "dds/DCPS/security/CommonUtilities.h"
00008 #include "dds/DCPS/SequenceIterator.h"
00009 #include "Err.h"
00010 #include <algorithm>
00011 #include <cstring>
00012 #include <fstream>
00013 #include <iterator>
00014 #include <cerrno>
00015 #include <openssl/pem.h>
00016 #include <openssl/x509v3.h>
00017 #include "../OpenSSL_legacy.h"
00018 #include <sstream>
00019
00020 namespace OpenDDS {
00021 namespace Security {
00022 namespace SSL {
00023 Certificate::Certificate(const std::string& uri,
00024 const std::string& password)
00025 : x_(NULL), original_bytes_(), dsign_algo_("")
00026 {
00027 DDS::Security::SecurityException ex;
00028 if (! load(ex, uri, password)) {
00029 ACE_ERROR((LM_WARNING, "(%P|%t) %C\n", ex.message.in()));
00030 }
00031 }
00032
00033 Certificate::Certificate(const DDS::OctetSeq& src)
00034 : x_(NULL), original_bytes_(), dsign_algo_("")
00035 {
00036 deserialize(src);
00037 }
00038
00039 Certificate::Certificate()
00040 : x_(NULL), original_bytes_(), dsign_algo_("")
00041 {
00042
00043 }
00044
00045 Certificate::Certificate(const Certificate& other)
00046 : x_(NULL), original_bytes_(), dsign_algo_("")
00047 {
00048 if (0 < other.original_bytes_.length()) {
00049 deserialize(other.original_bytes_);
00050 }
00051 }
00052
00053 Certificate::~Certificate()
00054 {
00055 if (x_) X509_free(x_);
00056 }
00057
00058 Certificate& Certificate::operator=(const Certificate& rhs)
00059 {
00060 if (this != &rhs) {
00061 if (rhs.x_ && (0 < rhs.original_bytes_.length())) {
00062 deserialize(rhs.original_bytes_);
00063 }
00064
00065 }
00066 return *this;
00067 }
00068
00069 bool Certificate::load(DDS::Security::SecurityException& ex,
00070 const std::string& uri,
00071 const std::string& password)
00072 {
00073 using namespace CommonUtilities;
00074
00075 if (x_) {
00076 set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: document already loaded");
00077 return false;
00078 }
00079
00080 URI uri_info(uri);
00081
00082 switch (uri_info.scheme) {
00083 case URI::URI_FILE:
00084 load_cert_bytes(uri_info.everything_else);
00085 x_ = x509_from_pem(original_bytes_, password);
00086 break;
00087
00088 case URI::URI_DATA:
00089 load_cert_data_bytes(uri_info.everything_else);
00090 x_ = x509_from_pem(original_bytes_, password);
00091 break;
00092
00093 case URI::URI_PKCS11:
00094 case URI::URI_UNKNOWN:
00095 default:
00096 ACE_ERROR((LM_WARNING,
00097 "(%P|%t) SSL::Certificate::load: WARNING: Unsupported URI scheme\n"));
00098
00099 break;
00100 }
00101
00102 if (! loaded()) {
00103 std::stringstream msg;
00104 msg << "SSL::Certificate::load: WARNING: Failed to load document supplied "
00105 "with URI '" << uri << "'";
00106 set_security_error(ex, -1, 0, msg.str().c_str());
00107 return false;
00108 }
00109
00110 int err = cache_dsign_algo();
00111 if (err) {
00112 set_security_error(ex, -1, 0, "SSL::Certificate::load: WARNING: Failed to cache signature algorithm");
00113 return false;
00114 }
00115 return true;
00116 }
00117
00118 int Certificate::validate(const Certificate& ca, unsigned long int flags) const
00119 {
00120 int result = X509_V_ERR_UNSPECIFIED;
00121
00122 if (x_) {
00123 if (ca.x_) {
00124 X509_STORE* certs = X509_STORE_new();
00125 if (certs) {
00126 X509_STORE_add_cert(certs, ca.x_);
00127
00128 X509_STORE_CTX* validation_ctx = X509_STORE_CTX_new();
00129 if (validation_ctx) {
00130 X509_STORE_CTX_init(validation_ctx, certs, x_, NULL);
00131 X509_STORE_CTX_set_flags(validation_ctx, flags);
00132
00133 if (X509_verify_cert(validation_ctx) == 1) {
00134 result = X509_V_OK;
00135
00136 } else {
00137 int err = X509_STORE_CTX_get_error(validation_ctx),
00138 depth = X509_STORE_CTX_get_error_depth(validation_ctx);
00139
00140 ACE_ERROR((LM_WARNING,
00141 ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING '%C' occurred using cert at "
00142 "depth '%i', validation failed.\n"),
00143 X509_verify_cert_error_string(err),
00144 depth));
00145
00146 result = err;
00147 }
00148
00149 X509_STORE_CTX_free(validation_ctx);
00150 }
00151
00152 X509_STORE_free(certs);
00153
00154 } else {
00155 OPENDDS_SSL_LOG_ERR("failed to create X509_STORE");
00156 }
00157
00158 } else {
00159 ACE_ERROR((LM_WARNING,
00160 ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING, passed-in CA has not loaded a "
00161 "certificate\n")));
00162 }
00163
00164 } else {
00165 ACE_ERROR((LM_WARNING,
00166 ACE_TEXT("(%P|%t) SSL::Certificate::verify: WARNING, a certificate must be loaded before "
00167 "it can be verified\n")));
00168 }
00169
00170 return result;
00171 }
00172
00173 class verify_implementation
00174 {
00175 public:
00176 explicit verify_implementation(EVP_PKEY* pkey)
00177 : public_key(pkey), md_ctx(NULL), pkey_ctx(NULL)
00178 {
00179 }
00180 ~verify_implementation() { EVP_MD_CTX_free(md_ctx); }
00181
00182 int operator()(const DDS::OctetSeq& src,
00183 const std::vector<const DDS::OctetSeq*>& expected_contents)
00184 {
00185 if (!public_key) return 1;
00186
00187 int pk_id = 0;
00188 std::vector<const DDS::OctetSeq*>::const_iterator i, n;
00189
00190 md_ctx = EVP_MD_CTX_new();
00191 if (!md_ctx) {
00192 OPENDDS_SSL_LOG_ERR("EVP_MD_CTX_new failed");
00193 return 1;
00194 }
00195
00196 EVP_MD_CTX_init(md_ctx);
00197
00198 if (1 != EVP_DigestVerifyInit(md_ctx, &pkey_ctx, EVP_sha256(), NULL,
00199 public_key)) {
00200 OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyInit failed");
00201 return 1;
00202 }
00203
00204
00205 pk_id = EVP_PKEY_id(public_key);
00206
00207 if (pk_id == EVP_PKEY_RSA) {
00208 if (1 !=
00209 EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING)) {
00210 OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_padding failed");
00211 return 1;
00212 }
00213
00214 if (1 != EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256())) {
00215 OPENDDS_SSL_LOG_ERR("EVP_PKEY_CTX_set_rsa_mgf1_md failed");
00216 return 1;
00217 }
00218 }
00219
00220 n = expected_contents.end();
00221 for (i = expected_contents.begin(); i != n; ++i) {
00222 if ((*i)->length() > 0) {
00223 if (1 != EVP_DigestVerifyUpdate(md_ctx, (*i)->get_buffer(),
00224 (*i)->length())) {
00225 OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyUpdate failed");
00226 return 1;
00227 }
00228 }
00229 }
00230
00231 int err = EVP_DigestVerifyFinal(md_ctx, src.get_buffer(), src.length());
00232 if (0 == err) {
00233 return 1;
00234
00235 } else if (1 != err) {
00236 OPENDDS_SSL_LOG_ERR("EVP_DigestVerifyFinal failed");
00237 return 1;
00238 }
00239
00240 return 0;
00241 }
00242
00243 private:
00244 EVP_PKEY* public_key;
00245 EVP_MD_CTX* md_ctx;
00246 EVP_PKEY_CTX* pkey_ctx;
00247 };
00248
00249 int Certificate::verify_signature(
00250 const DDS::OctetSeq& src,
00251 const std::vector<const DDS::OctetSeq*>& expected_contents) const
00252 {
00253 #ifdef OPENSSL_V_1_0
00254 struct EVP_PKEY_Handle {
00255 EVP_PKEY* pkey_;
00256 explicit EVP_PKEY_Handle(EVP_PKEY* pkey) : pkey_(pkey) {}
00257 operator EVP_PKEY*() { return pkey_; }
00258 ~EVP_PKEY_Handle() { EVP_PKEY_free(pkey_); }
00259 } pkey(X509_get_pubkey(x_));
00260 #else
00261 EVP_PKEY* pkey = X509_get0_pubkey(x_);
00262 #endif
00263 verify_implementation verify(pkey);
00264 return verify(src, expected_contents);
00265 }
00266
00267 int Certificate::subject_name_to_str(std::string& dst,
00268 unsigned long flags) const
00269 {
00270 int result = 1;
00271
00272 dst.clear();
00273
00274 if (x_) {
00275
00276 X509_NAME* name = X509_get_subject_name(x_);
00277 if (name) {
00278 BIO* buffer = BIO_new(BIO_s_mem());
00279 if (buffer) {
00280 int len = X509_NAME_print_ex(buffer, name, 0, flags);
00281 if (len > 0) {
00282 std::vector<char> tmp(len +
00283 1);
00284 len = BIO_gets(buffer, &tmp[0], len + 1);
00285 if (len > 0) {
00286 std::copy(
00287 tmp.begin(),
00288 tmp.end() -
00289 1,
00290 std::back_inserter(dst));
00291 result = 0;
00292
00293 } else {
00294 OPENDDS_SSL_LOG_ERR("failed to write BIO to string");
00295 }
00296
00297 } else {
00298 OPENDDS_SSL_LOG_ERR("failed to read X509_NAME into BIO buffer");
00299 }
00300
00301 BIO_free(buffer);
00302 }
00303 }
00304 }
00305
00306 return result;
00307 }
00308
00309 int Certificate::subject_name_digest(std::vector<CORBA::Octet>& dst) const
00310 {
00311 dst.clear();
00312
00313 if (!x_) return 1;
00314
00315
00316 X509_NAME* name = X509_get_subject_name(x_);
00317 if (NULL == name) {
00318 OPENDDS_SSL_LOG_ERR("X509_get_subject_name failed");
00319 return 1;
00320 }
00321
00322 std::vector<CORBA::Octet> tmp(EVP_MAX_MD_SIZE);
00323
00324 unsigned int len = 0;
00325 if (1 != X509_NAME_digest(name, EVP_sha256(), &tmp[0], &len)) {
00326 OPENDDS_SSL_LOG_ERR("X509_NAME_digest failed");
00327 return 1;
00328 }
00329
00330 dst.insert(dst.begin(), tmp.begin(), tmp.begin() + len);
00331
00332 return 0;
00333 }
00334
00335 const char* Certificate::keypair_algo() const
00336 {
00337
00338
00339 if (std::string("RSASSA-PSS-SHA256") == dsign_algo_) {
00340 return "RSA-2048";
00341
00342 } else if (std::string("ECDSA-SHA256") == dsign_algo_) {
00343 return "EC-prime256v1";
00344
00345 } else {
00346 return "UNKNOWN";
00347 }
00348 }
00349
00350 struct cache_dsign_algo_impl
00351 {
00352 cache_dsign_algo_impl() : pkey_(NULL), rsa_(NULL), ec_(NULL) {}
00353 ~cache_dsign_algo_impl()
00354 {
00355 EVP_PKEY_free(pkey_);
00356 RSA_free(rsa_);
00357 EC_KEY_free(ec_);
00358 }
00359
00360 int operator() (X509* cert, std::string& dst)
00361 {
00362 if (!cert) {
00363 ACE_ERROR((LM_WARNING,
00364 "(%P|%t) SSL::Certificate::cache_dsign_algo: WARNING, failed to "
00365 "get pubkey from X509 cert\n"));
00366 return 1;
00367 }
00368
00369 pkey_ = X509_get_pubkey(cert);
00370 if (!pkey_) {
00371 OPENDDS_SSL_LOG_ERR("cache_dsign_algo_impl::operator(): x509_get_pubkey failed");
00372 return 1;
00373 }
00374
00375 rsa_ = EVP_PKEY_get1_RSA(pkey_);
00376 if (rsa_) {
00377 dst = "RSASSA-PSS-SHA256";
00378 return 0;
00379 }
00380
00381 ec_ = EVP_PKEY_get1_EC_KEY(pkey_);
00382 if (ec_) {
00383 dst = "ECDSA-SHA256";
00384 return 0;
00385 }
00386
00387 ACE_ERROR((LM_WARNING,
00388 "(%P|%t) SSL::Certificate::cache_dsign_algo: WARNING, only RSASSA-PSS-SHA256 or "
00389 "ECDSA-SHA256 are currently supported signature/verification algorithms\n"));
00390
00391 return 1;
00392 }
00393
00394 private:
00395 EVP_PKEY* pkey_;
00396 RSA* rsa_;
00397 EC_KEY* ec_;
00398 };
00399
00400 int Certificate::cache_dsign_algo()
00401 {
00402 return cache_dsign_algo_impl()(x_, dsign_algo_);
00403 }
00404
00405 void Certificate::load_cert_bytes(const std::string& path)
00406 {
00407 std::ifstream in(path.c_str(), std::ios::binary);
00408
00409 if (in.fail()) {
00410 ACE_ERROR((LM_ERROR,
00411 "(%P|%t) Certificate::load_cert_bytes:"
00412 "WARNING: Failed to load file '%C'; errno: '%C'\n",
00413 path.c_str(), strerror(errno)));
00414 return;
00415 }
00416
00417 DCPS::SequenceBackInsertIterator<DDS::OctetSeq> back_inserter(original_bytes_);
00418
00419 std::copy((std::istreambuf_iterator<char>(in)),
00420 std::istreambuf_iterator<char>(),
00421 back_inserter);
00422
00423
00424
00425 *back_inserter = 0u;
00426 }
00427
00428 void Certificate::load_cert_data_bytes(const std::string& data)
00429 {
00430
00431
00432 original_bytes_.length(data.size() - 1);
00433 std::memcpy(original_bytes_.get_buffer(), &data[1],
00434 original_bytes_.length());
00435
00436
00437
00438 original_bytes_.length(original_bytes_.length() + 1);
00439 original_bytes_[original_bytes_.length() - 1] = 0;
00440 }
00441
00442 X509* Certificate::x509_from_pem(const std::string& path,
00443 const std::string& password)
00444 {
00445 X509* result = NULL;
00446
00447 BIO* filebuf = BIO_new_file(path.c_str(), "r");
00448 if (filebuf) {
00449 if (password != "") {
00450 result =
00451 PEM_read_bio_X509_AUX(filebuf, NULL, NULL, (void*)password.c_str());
00452 if (!result) {
00453 OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
00454 }
00455
00456 } else {
00457 result = PEM_read_bio_X509_AUX(filebuf, NULL, NULL, NULL);
00458 if (!result) {
00459 OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
00460 }
00461 }
00462
00463 BIO_free(filebuf);
00464
00465 } else {
00466 std::stringstream errmsg;
00467 errmsg << "failed to read file '" << path << "' using BIO_new_file";
00468 OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
00469 }
00470
00471 return result;
00472 }
00473
00474 X509* Certificate::x509_from_pem(const DDS::OctetSeq& bytes,
00475 const std::string& password)
00476 {
00477 X509* result = NULL;
00478
00479 BIO* filebuf = BIO_new(BIO_s_mem());
00480 do {
00481 if (filebuf) {
00482 if (0 >= BIO_write(filebuf, bytes.get_buffer(), bytes.length())) {
00483 OPENDDS_SSL_LOG_ERR("BIO_write failed");
00484 break;
00485 }
00486 if (password != "") {
00487 result = PEM_read_bio_X509_AUX(filebuf, NULL, NULL,
00488 (void*)password.c_str());
00489 if (!result) {
00490 OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
00491 break;
00492 }
00493
00494 } else {
00495 result = PEM_read_bio_X509_AUX(filebuf, NULL, NULL, NULL);
00496 if (!result) {
00497 OPENDDS_SSL_LOG_ERR("PEM_read_bio_X509_AUX failed");
00498 break;
00499 }
00500 }
00501
00502 } else {
00503 std::stringstream errmsg;
00504 errmsg << "BIO_new failed";
00505 OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
00506 break;
00507 }
00508
00509 } while (0);
00510
00511 BIO_free(filebuf);
00512
00513 return result;
00514 }
00515
00516 int Certificate::serialize(DDS::OctetSeq& dst) const
00517 {
00518 std::copy(DCPS::const_sequence_begin(original_bytes_),
00519 DCPS::const_sequence_end(original_bytes_),
00520 DCPS::back_inserter(dst));
00521
00522 if (dst.length() == original_bytes_.length()) {
00523 return 0;
00524 }
00525
00526 return 1;
00527 }
00528
00529 struct deserialize_impl
00530 {
00531 explicit deserialize_impl(const DDS::OctetSeq& src)
00532 : src_(src), buffer_(BIO_new(BIO_s_mem()))
00533 {}
00534
00535 ~deserialize_impl()
00536 {
00537 BIO_free(buffer_);
00538 }
00539
00540 int operator() (X509*& dst)
00541 {
00542 if (dst) {
00543 ACE_ERROR((LM_WARNING,
00544 "(%P|%t) SSL::Certificate::deserialize: WARNING, an X509 certificate "
00545 "has already been loaded\n"));
00546 return 1;
00547 }
00548
00549 if (0 == src_.length()) {
00550 ACE_ERROR((LM_WARNING,
00551 "(%P|%t) SSL::Certificate::deserialize: WARNING, source OctetSeq contains no data"));
00552 return 1;
00553 }
00554
00555 if (! buffer_) {
00556 OPENDDS_SSL_LOG_ERR("failed to allocate buffer with BIO_new");
00557 return 1;
00558 }
00559
00560 int len = BIO_write(buffer_, src_.get_buffer(), src_.length());
00561 if (len <= 0) {
00562 OPENDDS_SSL_LOG_ERR("failed to write OctetSeq to BIO");
00563 return 1;
00564 }
00565
00566 dst = PEM_read_bio_X509_AUX(buffer_, NULL, NULL, NULL);
00567 if (! dst) {
00568 OPENDDS_SSL_LOG_ERR("failed to read X509 from BIO");
00569 return 1;
00570 }
00571
00572 return 0;
00573 }
00574
00575 private:
00576 const DDS::OctetSeq& src_;
00577 BIO* buffer_;
00578 };
00579
00580 int Certificate::deserialize(const DDS::OctetSeq& src)
00581 {
00582 int err = deserialize_impl(src)(x_) || cache_dsign_algo();
00583 if (! err) {
00584 original_bytes_ = src;
00585 }
00586
00587 return err;
00588 }
00589
00590 std::ostream& operator<<(std::ostream& lhs, const Certificate& rhs)
00591 {
00592 if (rhs.x_) {
00593 lhs << "Certificate: { is_ca? '"
00594 << (X509_check_ca(rhs.x_) ? "yes" : "no") << "'; }";
00595
00596 } else {
00597 lhs << "NULL";
00598 }
00599 return lhs;
00600 }
00601
00602 bool operator==(const Certificate& lhs, const Certificate& rhs)
00603 {
00604 if (lhs.x_ && rhs.x_) {
00605 return (0 == X509_cmp(lhs.x_, rhs.x_)) &&
00606 (lhs.original_bytes_ == rhs.original_bytes_);
00607 }
00608 return (lhs.x_ == rhs.x_) &&
00609 (lhs.original_bytes_ == rhs.original_bytes_);
00610 }
00611 }
00612 }
00613 }