00001
00002
00003
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
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
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
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 }
00361 }
00362 }