SignedDocument.cpp

Go to the documentation of this file.
00001 /*
00002  * Distributed under the OpenDDS License.
00003  * See: http://www.OpenDDS.org/license.html
00004  */
00005 
00006 #include "SignedDocument.h"
00007 #include "dds/DCPS/security/CommonUtilities.h"
00008 #include "dds/DCPS/SequenceIterator.h"
00009 #include "Err.h"
00010 #include <openssl/pem.h>
00011 #include <cstring>
00012 #include <sstream>
00013 #include <iterator>
00014 #include <algorithm>
00015 #include <fstream>
00016 
00017 namespace OpenDDS {
00018 namespace Security {
00019 namespace SSL {
00020 
00021   SignedDocument::SignedDocument(const std::string& uri)
00022     : doc_(NULL), original_(), verifiable_("")
00023   {
00024     DDS::Security::SecurityException ex;
00025     if (! load(uri, ex)) {
00026       ACE_ERROR((LM_WARNING, "(%P|%t) %C\n", ex.message.in()));
00027     }
00028   }
00029 
00030   SignedDocument::SignedDocument()
00031     : doc_(NULL), original_(), verifiable_("")
00032   {
00033   }
00034 
00035   SignedDocument::SignedDocument(const DDS::OctetSeq& src)
00036     : doc_(NULL), original_(), verifiable_("")
00037   {
00038     deserialize(src);
00039   }
00040 
00041   SignedDocument::SignedDocument(const SignedDocument& rhs)
00042   : doc_(NULL), original_(), verifiable_("")
00043   {
00044     if (0 < rhs.original_.length()) {
00045       deserialize(rhs.original_);
00046     }
00047   }
00048 
00049   SignedDocument::~SignedDocument()
00050   {
00051     if (doc_) PKCS7_free(doc_);
00052   }
00053 
00054   SignedDocument& SignedDocument::operator=(const SignedDocument& rhs)
00055   {
00056     if (this != &rhs) {
00057       if (0 < rhs.original_.length()) {
00058         deserialize(rhs.original_);
00059       }
00060     }
00061     return *this;
00062   }
00063 
00064   bool SignedDocument::load(const std::string& uri, DDS::Security::SecurityException& ex)
00065   {
00066     using namespace CommonUtilities;
00067 
00068     if (doc_) {
00069       set_security_error(ex, -1, 0, "SSL::SignedDocument::load: WARNING: document already loaded");
00070       return false;
00071     }
00072 
00073     URI uri_info(uri);
00074 
00075     switch (uri_info.scheme) {
00076       case URI::URI_FILE:
00077         PKCS7_from_SMIME_file(uri_info.everything_else);
00078         break;
00079 
00080       case URI::URI_DATA:
00081         deserialize(uri_info.everything_else);
00082         break;
00083 
00084       case URI::URI_PKCS11:
00085       case URI::URI_UNKNOWN:
00086       default:
00087         ACE_ERROR((LM_WARNING,
00088                   "(%P|%t) SSL::SignedDocument::load: WARNING: Unsupported URI scheme\n"));
00089         break;
00090     }
00091 
00092     if (! loaded()) {
00093       std::stringstream msg;
00094       msg << "SSL::SignedDocument::load: WARNING: Failed to load document supplied "
00095              "with URI '"  << uri << "'";
00096       set_security_error(ex, -1, 0, msg.str().c_str());
00097       return false;
00098     }
00099 
00100     return true;
00101   }
00102 
00103   void SignedDocument::get_original(std::string& dst) const
00104   {
00105     dst = "";
00106 
00107     std::copy(DCPS::const_sequence_begin(original_),
00108               DCPS::const_sequence_end(original_),
00109               std::back_inserter(dst));
00110   }
00111 
00112   bool SignedDocument::get_original_minus_smime(std::string& dst) const
00113   {
00114     const std::string start_str("Content-Type: text/plain"),
00115                       end_str("dds>");
00116 
00117     get_original(dst);
00118 
00119     size_t found_begin = dst.find(start_str);
00120 
00121     if (found_begin != std::string::npos) {
00122       dst.erase(0, found_begin + start_str.length());
00123 
00124       const char* t = " \t\n\r\f\v";
00125 
00126       dst.erase(0, dst.find_first_not_of(t));
00127     }
00128     else {
00129       return false;
00130     }
00131 
00132     size_t found_end = dst.find(end_str);
00133 
00134     if (found_end != std::string::npos) {
00135       dst.erase(found_end + end_str.length());
00136     }
00137     else {
00138       return false;
00139     }
00140 
00141     return true;
00142   }
00143 
00144   class verify_signature_impl
00145   {
00146    public:
00147     verify_signature_impl(PKCS7* doc, const std::string& content)
00148       : doc_(doc),
00149         content_(content),
00150         store_(NULL),
00151         store_ctx_(NULL),
00152         reader_(NULL)
00153     {
00154       if (NULL == (store_ = X509_STORE_new())) {
00155         OPENDDS_SSL_LOG_ERR("X509_STORE_new failed");
00156       }
00157       if (NULL == (store_ctx_ = X509_STORE_CTX_new())) {
00158         OPENDDS_SSL_LOG_ERR("X509_STORE_CTX_new failed");
00159       }
00160       if (NULL == (reader_ = BIO_new(BIO_s_mem()))) {
00161         OPENDDS_SSL_LOG_ERR("BIO_new failed");
00162       }
00163     }
00164 
00165     ~verify_signature_impl()
00166     {
00167       X509_STORE_CTX_free(store_ctx_);
00168       X509_STORE_free(store_);
00169       BIO_free(reader_);
00170     }
00171 
00172     int operator()(const Certificate& ca, unsigned long int flags = 0)
00173     {
00174       if (!doc_) return 1;
00175       if (0 == content_.length()) return 1;
00176 
00177       if (1 != X509_STORE_add_cert(store_, ca.x_)) {
00178         OPENDDS_SSL_LOG_ERR("X509_STORE_add_cert failed");
00179         return 1;
00180       }
00181 
00182       size_t len = BIO_write(reader_, content_.c_str(), content_.length());
00183       if (len <= 0) {
00184         OPENDDS_SSL_LOG_ERR("BIO_write failed");
00185         return 1;
00186       }
00187 
00188       if (1 != PKCS7_verify(doc_, NULL, store_, reader_, NULL, flags)) {
00189         OPENDDS_SSL_LOG_ERR("PKCS7_verify failed");
00190         return 1;
00191       }
00192       return 0;
00193     }
00194 
00195    private:
00196     PKCS7* doc_;
00197     const std::string& content_;
00198 
00199     X509_STORE* store_;
00200     X509_STORE_CTX* store_ctx_;
00201     BIO* reader_;
00202   };
00203 
00204   int SignedDocument::verify_signature(const Certificate& ca) const
00205   {
00206     verify_signature_impl verify(doc_, verifiable_);
00207     return verify(ca);
00208   }
00209 
00210   int SignedDocument::serialize(DDS::OctetSeq& dst) const
00211   {
00212     std::copy(DCPS::const_sequence_begin(original_),
00213               DCPS::const_sequence_end(original_),
00214               DCPS::back_inserter(dst));
00215 
00216     if (dst.length() == original_.length()) {
00217       return 0;
00218     }
00219 
00220     return 1;
00221   }
00222 
00223   int SignedDocument::deserialize(const DDS::OctetSeq& src)
00224   {
00225     if (doc_) {
00226       ACE_ERROR((LM_WARNING, "(%P|%t) SSL::Certificate::deserialize: WARNING, an X509 certificate has already been loaded\n"));
00227       return 1;
00228     }
00229 
00230     // Assume the trailing null is already set
00231 
00232     std::copy(DCPS::const_sequence_begin(src),
00233               DCPS::const_sequence_end(src),
00234               DCPS::back_inserter(original_));
00235 
00236     if (0 < original_.length()) {
00237       PKCS7_from_data(original_);
00238     }
00239 
00240     return 0;
00241   }
00242 
00243   int SignedDocument::deserialize(const std::string& src)
00244   {
00245     if (doc_) {
00246       ACE_ERROR((LM_WARNING, "(%P|%t) SSL::Certificate::deserialize: WARNING, an X509 certificate has already been loaded\n"));
00247       return 1;
00248     }
00249 
00250     DCPS::SequenceBackInsertIterator<DDS::OctetSeq> back_inserter(original_);
00251     std::copy(src.begin(), src.end(), back_inserter);
00252 
00253     // To appease the other DDS security implementations
00254     *back_inserter = 0u;
00255 
00256     if (0 < original_.length()) {
00257       PKCS7_from_data(original_);
00258       if (! doc_) {
00259         return 1;
00260       }
00261     }
00262     return 0;
00263   }
00264 
00265   int SignedDocument::cache_verifiable(BIO* from)
00266   {
00267     if (!doc_ || !from) {
00268       return 1;
00269     }
00270 
00271     unsigned char tmp[32] = { 0 };
00272     int len = 0;
00273     while ((len = BIO_read(from, tmp, sizeof(tmp))) > 0) {
00274       verifiable_.insert(verifiable_.end(), tmp, tmp + len);
00275     }
00276 
00277     if (0 < verifiable_.length()) {
00278       return 0;
00279     }
00280 
00281     return 1;
00282   }
00283 
00284   PKCS7* SignedDocument::PKCS7_from_SMIME_file(const std::string& path)
00285   {
00286     std::ifstream in(path.c_str(), std::ios::binary);
00287 
00288     DCPS::SequenceBackInsertIterator<DDS::OctetSeq> back_inserter(original_);
00289 
00290     std::copy((std::istreambuf_iterator<char>(in)),
00291                std::istreambuf_iterator<char>(),
00292                back_inserter);
00293 
00294     if (in.fail()) {
00295       ACE_ERROR((LM_ERROR,
00296                 "(%P|%t) SignedDocument::PKCS7_from_SMIME_file:"
00297                 "WARNING: Failed to load file '%C'; errno: '%C'\n",
00298                 path.c_str(), strerror(errno)));
00299       return NULL;
00300     }
00301 
00302     // To appease the other DDS security implementations
00303     *back_inserter = 0u;
00304 
00305     if (0 < original_.length()) {
00306       return PKCS7_from_data(original_);
00307     }
00308 
00309     return NULL;
00310   }
00311 
00312   PKCS7* SignedDocument::PKCS7_from_data(const DDS::OctetSeq& s_mime_data)
00313   {
00314     if (doc_) {
00315       ACE_ERROR((LM_ERROR,
00316                  "(%P|%t) SignedDocument::PKCS7_from_data: "
00317                  "WARNING: document has already been constructed\n"));
00318       return NULL;
00319     }
00320 
00321     BIO* filebuf = BIO_new(BIO_s_mem());
00322 
00323     if (filebuf) {
00324       if (0 >= BIO_write(filebuf, s_mime_data.get_buffer(),
00325                          s_mime_data.length())) {
00326         OPENDDS_SSL_LOG_ERR("BIO_write failed");
00327       }
00328 
00329       BIO* cache_this = NULL;
00330 
00331       doc_ = SMIME_read_PKCS7(filebuf, &cache_this);
00332 
00333       if (!doc_) {
00334         OPENDDS_SSL_LOG_ERR("SMIME_read_PKCS7 failed");
00335       }
00336 
00337       if (0 != cache_verifiable(cache_this)) {
00338         ACE_ERROR((LM_ERROR,
00339                    "(%P|%t) SignedDocument::PKCS7_from_data: "
00340                    "WARNING: failed to cache verifiable part of S/MIME data\n"));
00341       }
00342 
00343       BIO_free(filebuf);
00344       BIO_free(cache_this);
00345 
00346     } else {
00347       std::stringstream errmsg;
00348       errmsg << "failed to create data '" << s_mime_data << "' using BIO_new";
00349       OPENDDS_SSL_LOG_ERR(errmsg.str().c_str());
00350     }
00351 
00352     return doc_;
00353   }
00354 
00355   bool operator==(const SignedDocument& lhs, const SignedDocument& rhs)
00356   {
00357     return lhs.original_ == rhs.original_ && lhs.verifiable_ == rhs.verifiable_;
00358   }
00359 
00360 }  // namespace SSL
00361 }  // namespace Security
00362 }  // namespace OpenDDS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1