AuthenticationBuiltInImpl.cpp

Go to the documentation of this file.
00001 /*
00002 *
00003 *
00004 * Distributed under the OpenDDS License.
00005 * See: http://www.opendds.org/license.html
00006 */
00007 
00008 #include "AuthenticationBuiltInImpl.h"
00009 
00010 #include "CommonUtilities.h"
00011 #include "TokenReader.h"
00012 #include "TokenWriter.h"
00013 #include "SSL/Utils.h"
00014 
00015 #include "dds/DCPS/GuidUtils.h"
00016 #include "dds/DCPS/LocalObject.h"
00017 #include "dds/DCPS/Serializer.h"
00018 
00019 #include "dds/DCPS/RTPS/RtpsCoreC.h"
00020 #include "dds/DCPS/RTPS/RtpsCoreTypeSupportImpl.h"
00021 
00022 #include "ace/config-macros.h"
00023 #include "ace/Guard_T.h"
00024 
00025 #include <sstream>
00026 #include <vector>
00027 #include <algorithm>
00028 #include <cstdio>
00029 
00030 OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
00031 
00032 namespace OpenDDS {
00033 namespace Security {
00034 
00035 using CommonUtilities::set_security_error;
00036 
00037 static bool challenges_match(const DDS::OctetSeq& c1, const DDS::OctetSeq& c2);
00038 
00039 static void extract_participant_guid_from_cpdata(const DDS::OctetSeq& cpdata, DCPS::GUID_t& dst);
00040 
00041 static bool validate_topic_data_guid(const DDS::OctetSeq& cpdata,
00042                                      const std::vector<unsigned char>& subject_name_hash,
00043                                      DDS::Security::SecurityException& ex);
00044 
00045 const std::string Auth_Plugin_Name("DDS:Auth:PKI-DH");
00046 const std::string Auth_Plugin_Major_Version("1");
00047 const std::string Auth_Plugin_Minor_Version("0");
00048 
00049 const std::string Identity_Status_Token_Class_Id("DDS:Auth:PKI-DH:1.0");
00050 const std::string Auth_Peer_Cred_Token_Class_Id("DDS:Auth:PKI-DH:1.0");
00051 const std::string Auth_Request_Class_Ext("AuthReq");
00052 const std::string Handshake_Request_Class_Ext("Req");
00053 const std::string Handshake_Reply_Class_Ext("Reply");
00054 const std::string Handshake_Final_Class_Ext("Final");
00055 
00056 struct SharedSecret : DCPS::LocalObject<DDS::Security::SharedSecretHandle> {
00057 
00058   SharedSecret(DDS::OctetSeq challenge1,
00059                DDS::OctetSeq challenge2,
00060                DDS::OctetSeq sharedSecret)
00061     : challenge1_(challenge1)
00062     , challenge2_(challenge2)
00063     , shared_secret_(sharedSecret)
00064   {}
00065 
00066   DDS::OctetSeq* challenge1() { return new DDS::OctetSeq(challenge1_); }
00067   DDS::OctetSeq* challenge2() { return new DDS::OctetSeq(challenge2_); }
00068   DDS::OctetSeq* sharedSecret() { return new DDS::OctetSeq(shared_secret_); }
00069 
00070   DDS::OctetSeq challenge1_, challenge2_, shared_secret_;
00071 };
00072 
00073 AuthenticationBuiltInImpl::AuthenticationBuiltInImpl()
00074 : listener_ptr_()
00075 , identity_mutex_()
00076 , handshake_mutex_()
00077 , handle_mutex_()
00078 , next_handle_(1)
00079 {
00080 }
00081 
00082 AuthenticationBuiltInImpl::~AuthenticationBuiltInImpl()
00083 {
00084 
00085 }
00086 
00087 ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::validate_local_identity(
00088   ::DDS::Security::IdentityHandle & local_identity_handle,
00089   ::OpenDDS::DCPS::GUID_t & adjusted_participant_guid,
00090   ::DDS::Security::DomainId_t /*domain_id*/,
00091   const ::DDS::DomainParticipantQos & participant_qos,
00092   const ::OpenDDS::DCPS::GUID_t & candidate_participant_guid,
00093   ::DDS::Security::SecurityException & ex)
00094 {
00095   DDS::Security::ValidationResult_t result = DDS::Security::VALIDATION_FAILED;
00096 
00097   LocalAuthCredentialData::shared_ptr credentials = DCPS::make_rch<LocalAuthCredentialData>();
00098   if (! credentials->load_credentials(participant_qos.property.value, ex)) {
00099     return result;
00100   }
00101 
00102   if (credentials->validate()) {
00103     if (candidate_participant_guid != DCPS::GUID_UNKNOWN) {
00104 
00105       int err = SSL::make_adjusted_guid(candidate_participant_guid,
00106                                         adjusted_participant_guid,
00107                                         credentials->get_participant_cert());
00108       if (! err) {
00109         local_identity_handle = get_next_handle();
00110 
00111         LocalParticipantData::shared_ptr local_participant = DCPS::make_rch<LocalParticipantData>();
00112         local_participant->participant_guid = adjusted_participant_guid;
00113         local_participant->credentials = credentials;
00114 
00115         {
00116           ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00117           local_participants_[local_identity_handle] = local_participant;
00118         }
00119 
00120         result = DDS::Security::VALIDATION_OK;
00121 
00122       } else {
00123         set_security_error(ex, -1, 0, "SSL::make_adjusted_guid failed");
00124       }
00125 
00126     } else {
00127         set_security_error(ex, -1, 0, "GUID_UNKNOWN passed in for candidate_participant_guid");
00128     }
00129 
00130   } else {
00131       set_security_error(ex, -1, 0, "local-credential-data failed validation");
00132   }
00133 
00134   return result;
00135 }
00136 
00137 ::CORBA::Boolean AuthenticationBuiltInImpl::get_identity_token(
00138   ::DDS::Security::IdentityToken & identity_token,
00139   ::DDS::Security::IdentityHandle handle,
00140   ::DDS::Security::SecurityException & ex)
00141 {
00142   ::CORBA::Boolean status = false;
00143 
00144   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00145 
00146   LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
00147   if (local_data) {
00148     const LocalAuthCredentialData& local_credential_data = *(local_data->credentials);
00149 
00150     const SSL::Certificate& pcert = local_credential_data.get_participant_cert();
00151     const SSL::Certificate& cacert = local_credential_data.get_ca_cert();
00152 
00153     std::string tmp;
00154 
00155     OpenDDS::Security::TokenWriter identity_wrapper(identity_token, "DDS:Auth:PKI-DH:1.0");
00156 
00157     pcert.subject_name_to_str(tmp);
00158     identity_wrapper.add_property("dds.cert.sn", tmp.c_str());
00159     identity_wrapper.add_property("dds.cert.algo", pcert.keypair_algo());
00160 
00161     cacert.subject_name_to_str(tmp);
00162     identity_wrapper.add_property("dds.ca.sn", tmp.c_str());
00163     identity_wrapper.add_property("dds.ca.algo", cacert.keypair_algo());
00164 
00165     status = true;
00166 
00167   } else {
00168     set_security_error(ex, -1, 0, "Unknown Identity handle");
00169   }
00170   return status;
00171 }
00172 
00173 ::CORBA::Boolean AuthenticationBuiltInImpl::get_identity_status_token(
00174   ::DDS::Security::IdentityStatusToken&,
00175   ::DDS::Security::IdentityHandle handle,
00176   ::DDS::Security::SecurityException & ex)
00177 {
00178   ::CORBA::Boolean status = false;
00179 
00180   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00181 
00182   // Populate a simple version of an IdentityStatusToken as long as the handle is known
00183   LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
00184   if (local_data) {
00185 
00186     // TODO: Pending AuthenticationListener support (see security spec. 8.3.2.2).
00187     // This routine will most likely populate the IdentityStatusToken with
00188     // useful data once this has been completed. For now it's a glorified no-op!
00189 
00190     status = true;
00191   } else {
00192     set_security_error(ex, -1, 0, "Unknown Identity handle");
00193   }
00194 
00195   return status;
00196 }
00197 
00198 ::CORBA::Boolean AuthenticationBuiltInImpl::set_permissions_credential_and_token(
00199   ::DDS::Security::IdentityHandle handle,
00200   const ::DDS::Security::PermissionsCredentialToken & permissions_credential,
00201   const ::DDS::Security::PermissionsToken & permissions_token,
00202   ::DDS::Security::SecurityException & ex)
00203 {
00204   ACE_UNUSED_ARG(permissions_token);
00205 
00206   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00207 
00208   LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
00209   if (! local_data) {
00210     set_security_error(ex, -1, 0, "Identity handle not recognized");
00211     return false;
00212   }
00213 
00214   return local_data->credentials->load_access_permissions(permissions_credential, ex);
00215 }
00216 
00217 ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::validate_remote_identity(
00218   ::DDS::Security::IdentityHandle & remote_identity_handle,
00219   ::DDS::Security::AuthRequestMessageToken & local_auth_request_token,
00220   const ::DDS::Security::AuthRequestMessageToken & remote_auth_request_token,
00221   ::DDS::Security::IdentityHandle local_identity_handle,
00222   const ::DDS::Security::IdentityToken & remote_identity_token,
00223   const ::OpenDDS::DCPS::GUID_t & remote_participant_guid,
00224   ::DDS::Security::SecurityException & ex)
00225 {
00226   DDS::Security::ValidationResult_t result = DDS::Security::VALIDATION_OK;
00227 
00228   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00229 
00230   LocalParticipantData::shared_ptr local_data = get_local_participant(local_identity_handle);
00231   if (local_data) {
00232     if (check_class_versions(remote_identity_token.class_id)) {
00233 
00234       // Make sure that a remote_participant_guid has not already been assigned a
00235       // remote-identity-handle before creating a new one.
00236 
00237       RemoteParticipantMap::iterator begin = local_data->validated_remotes.begin(),
00238                                      end = local_data->validated_remotes.end(),
00239                                      found = std::find_if(begin, end,
00240                                                           was_guid_validated(remote_participant_guid));
00241       if (found != end) {
00242         remote_identity_handle = found->first;
00243         local_auth_request_token = found->second->local_auth_request;
00244 
00245         if (is_handshake_initiator(local_data->participant_guid, remote_participant_guid)) {
00246           result = DDS::Security::VALIDATION_PENDING_HANDSHAKE_REQUEST;
00247 
00248         } else {
00249           result = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00250         }
00251 
00252       } else {
00253 
00254         TokenReader remote_request(remote_auth_request_token);
00255         if (remote_request.is_nil()) {
00256 
00257           DDS::OctetSeq nonce;
00258           int err = SSL::make_nonce_256(nonce);
00259           if (! err) {
00260             TokenWriter auth_req_wrapper(local_auth_request_token, build_class_id(Auth_Request_Class_Ext));
00261 
00262             auth_req_wrapper.add_bin_property("future_challenge", nonce);
00263 
00264           } else {
00265             set_security_error(ex, -1, 0, "Failed to generate 256-bit nonce value for future_challenge property");
00266 
00267             result = DDS::Security::VALIDATION_FAILED;
00268           }
00269 
00270         } else {
00271           local_auth_request_token = DDS::Security::Token();
00272         }
00273 
00274         if (result == DDS::Security::VALIDATION_OK) {
00275 
00276           // Retain all of the data needed for a handshake with the remote participant
00277           RemoteParticipantData::shared_ptr remote_participant = DCPS::make_rch<RemoteParticipantData>();
00278           remote_participant->participant_guid = remote_participant_guid;
00279           remote_participant->local_participant = local_identity_handle;
00280           remote_participant->local_auth_request = local_auth_request_token;
00281           remote_participant->remote_auth_request = remote_auth_request_token;
00282 
00283           remote_identity_handle = get_next_handle();
00284           local_data->validated_remotes[remote_identity_handle] = remote_participant;
00285 
00286           if (is_handshake_initiator(local_data->participant_guid, remote_participant_guid)) {
00287             result = DDS::Security::VALIDATION_PENDING_HANDSHAKE_REQUEST;
00288 
00289           } else {
00290             result = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00291           }
00292         }
00293       }
00294 
00295     } else {
00296       set_security_error(ex, -1, 0, "Remote class ID is not compatible");
00297       result = DDS::Security::VALIDATION_FAILED;
00298     }
00299 
00300   } else {
00301     set_security_error(ex, -1, 0, "Local participant ID not found");
00302     result = DDS::Security::VALIDATION_FAILED;
00303   }
00304 
00305   return result;
00306 }
00307 
00308 ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::begin_handshake_request(
00309   ::DDS::Security::HandshakeHandle & handshake_handle,
00310   ::DDS::Security::HandshakeMessageToken & handshake_message,
00311   ::DDS::Security::IdentityHandle initiator_identity_handle,
00312   ::DDS::Security::IdentityHandle replier_identity_handle,
00313   const ::DDS::OctetSeq & serialized_local_participant_data,
00314   ::DDS::Security::SecurityException & ex)
00315 {
00316   if (serialized_local_participant_data.length() == 0) {
00317     set_security_error(ex, -1, 0, "No participant data provided");
00318     return DDS::Security::VALIDATION_FAILED;
00319   }
00320 
00321   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00322 
00323   HandshakeDataPair handshake_data = make_handshake_pair(initiator_identity_handle, replier_identity_handle);
00324 
00325   if (! handshake_data.first) {
00326     set_security_error(ex, -1, 0, "Unknown local participant");
00327     return DDS::Security::VALIDATION_FAILED;
00328   }
00329 
00330   if (! handshake_data.second) {
00331     set_security_error(ex, -1, 0, "Unknown remote participant");
00332     return DDS::Security::VALIDATION_FAILED;
00333   }
00334 
00335   LocalParticipantData& local_data = *(handshake_data.first);
00336   RemoteParticipantData& remote_data = *(handshake_data.second);
00337 
00338   const LocalAuthCredentialData& local_credential_data = *(local_data.credentials);
00339 
00340   SSL::DiffieHellman::unique_ptr diffie_hellman(new SSL::DiffieHellman(new SSL::ECDH_PRIME_256_V1_CEUM));
00341 
00342   OpenDDS::Security::TokenWriter message_out(handshake_message, build_class_id(Handshake_Request_Class_Ext));
00343 
00344   // Compute hash_c1 and store for later
00345 
00346   DDS::OctetSeq hash_c1;
00347 
00348   {
00349     CredentialHash hash(local_credential_data.get_participant_cert(),
00350                         *diffie_hellman,
00351                         serialized_local_participant_data,
00352                         local_credential_data.get_access_permissions());
00353 
00354     int err = hash(hash_c1);
00355     if (err) {
00356       set_security_error(ex, -1, 0, "Failed to generate credential-hash 'hash_c1'");
00357       return DDS::Security::VALIDATION_FAILED;
00358     }
00359   }
00360 
00361   message_out.add_bin_property("c.id", local_credential_data.get_participant_cert().original_bytes());
00362   message_out.add_bin_property("c.perm", local_credential_data.get_access_permissions());
00363   message_out.add_bin_property("c.pdata", serialized_local_participant_data);
00364   message_out.add_bin_property("c.dsign_algo", local_credential_data.get_participant_cert().dsign_algo());
00365   message_out.add_bin_property("c.kagree_algo", diffie_hellman->kagree_algo());
00366   message_out.add_bin_property("hash_c1", hash_c1);
00367 
00368   DDS::OctetSeq dhpub;
00369   diffie_hellman->pub_key(dhpub);
00370   message_out.add_bin_property("dh1", dhpub);
00371 
00372   OpenDDS::Security::TokenReader auth_wrapper(remote_data.local_auth_request);
00373   if (auth_wrapper.is_nil()) {
00374     DDS::OctetSeq nonce;
00375     int err = SSL::make_nonce_256(nonce);
00376     if (! err) {
00377       message_out.add_bin_property("challenge1", nonce);
00378 
00379     } else {
00380       set_security_error(ex, -1, 0, "Failed to generate 256-bit nonce value for challenge1 property");
00381       return DDS::Security::VALIDATION_FAILED;
00382     }
00383 
00384   } else {
00385     const DDS::OctetSeq& challenge_data = auth_wrapper.get_bin_property_value("future_challenge");
00386     message_out.add_bin_property("challenge1", challenge_data);
00387 
00388   }
00389 
00390   remote_data.initiator_identity = initiator_identity_handle;
00391   remote_data.replier_identity = replier_identity_handle;
00392   remote_data.state = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00393   remote_data.request = handshake_message;
00394   remote_data.reply = DDS::Security::Token();
00395   remote_data.diffie_hellman = DCPS::move(diffie_hellman);
00396   remote_data.hash_c1 = hash_c1;
00397 
00398   handshake_handle = get_next_handle();
00399   {
00400     ACE_Guard<ACE_Thread_Mutex> identity_data_guard(handshake_mutex_);
00401     handshake_data_[handshake_handle] = handshake_data;
00402   }
00403 
00404   return DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00405 }
00406 
00407 void extract_participant_guid_from_cpdata(const DDS::OctetSeq& cpdata, DCPS::GUID_t& dst)
00408 {
00409   dst = DCPS::GUID_UNKNOWN;
00410 
00411   ACE_Message_Block buffer(reinterpret_cast<const char*>(cpdata.get_buffer()), cpdata.length());
00412   buffer.wr_ptr(cpdata.length());
00413   OpenDDS::DCPS::Serializer serializer(&buffer, DCPS::Serializer::SWAP_BE, DCPS::Serializer::ALIGN_CDR);
00414   RTPS::ParameterList params;
00415 
00416   if (serializer >> params) {
00417     for (size_t i = 0; i < params.length(); ++i) {
00418       const RTPS::Parameter& p = params[i];
00419 
00420       if (p._d() == RTPS::PID_PARTICIPANT_GUID) {
00421         dst = p.guid();
00422         break;
00423       }
00424     }
00425 
00426   } else {
00427     ACE_ERROR((LM_WARNING,
00428                ACE_TEXT("(%P|%t) WARNING: extract_participant_guid_from_cpdata, ")
00429                ACE_TEXT("failed to deserialize guid from cpdata.\n")));
00430   }
00431 
00432 }
00433 
00434 bool validate_topic_data_guid(const DDS::OctetSeq& cpdata,
00435                               const std::vector<unsigned char>& subject_name_hash,
00436                               DDS::Security::SecurityException& ex)
00437 {
00438   if (cpdata.length() > 5u) { /* Enough to withstand the hash-comparison below */
00439 
00440     DCPS::GUID_t remote_participant_guid;
00441     extract_participant_guid_from_cpdata(cpdata, remote_participant_guid);
00442 
00443     const DCPS::GuidPrefix_t& prefix = remote_participant_guid.guidPrefix;
00444 
00445     /* Make sure first bit is set */
00446 
00447     if ((prefix[0] & 0x80) != 0x80) {
00448       set_security_error(ex, -1, 0, "Malformed participant_guid in 'c.pdata'; First bit must be set.");
00449       return false;
00450     }
00451 
00452     /* Check the following 47 bits match the subject-hash */
00453 
00454     /* First byte needs to remove the manually-set first-bit before comparison */
00455     if ((prefix[0] & 0x7F) != SSL::offset_1bit(&subject_name_hash[0], 0)) {
00456       set_security_error(ex, -1, 0, "First byte of participant_guid in 'c.pdata' does not match bits of subject-name hash in 'c.id'");
00457       return false;
00458     }
00459     for (size_t i = 1; i <= 5u; ++i) { /* Compare remaining 5 bytes */
00460       if (prefix[i] != SSL::offset_1bit(&subject_name_hash[0], i)) { /* Slide the hash to the right 1 so it aligns with the guid prefix */
00461         set_security_error(ex, -1, 0, "Bits 2 - 48 of 'c.pdata' participant_guid does not match first 47 bits of subject-name hash in 'c.id'");
00462         return false;
00463       }
00464     }
00465 
00466   } else {
00467     set_security_error(ex, -1, 0, "Data missing in 'c.pdata'");
00468     return false;
00469   }
00470 
00471   return true;
00472 }
00473 
00474 static void make_reply_signature_sequence(const DDS::OctetSeq& hash_c2,
00475                                           const DDS::OctetSeq& challenge2,
00476                                           const DDS::OctetSeq& dh2,
00477                                           const DDS::OctetSeq& challenge1,
00478                                           const DDS::OctetSeq& dh1,
00479                                           const DDS::OctetSeq& hash_c1,
00480                                           DDS::BinaryPropertySeq& dst)
00481 {
00482   DCPS::SequenceBackInsertIterator<DDS::BinaryPropertySeq> inserter(dst);
00483 
00484   {
00485     DDS::BinaryProperty_t p;
00486     p.name = "hash_c2";
00487     p.value = hash_c2;
00488     p.propagate = true;
00489     *inserter = p;
00490   }
00491 
00492   {
00493     DDS::BinaryProperty_t p;
00494     p.name = "challenge2";
00495     p.value = challenge2;
00496     p.propagate = true;
00497     *inserter = p;
00498   }
00499 
00500   {
00501     DDS::BinaryProperty_t p;
00502     p.name = "dh2";
00503     p.value = dh2;
00504     p.propagate = true;
00505     *inserter = p;
00506   }
00507 
00508   {
00509     DDS::BinaryProperty_t p;
00510     p.name = "challenge1";
00511     p.value = challenge1;
00512     p.propagate = true;
00513     *inserter = p;
00514   }
00515 
00516   {
00517     DDS::BinaryProperty_t p;
00518     p.name = "dh1";
00519     p.value = dh1;
00520     p.propagate = true;
00521     *inserter = p;
00522   }
00523 
00524   {
00525     DDS::BinaryProperty_t p;
00526     p.name = "hash_c1";
00527     p.value = hash_c1;
00528     p.propagate = true;
00529     *inserter = p;
00530   }
00531 }
00532 
00533 static void make_final_signature_sequence(const DDS::OctetSeq& hash_c1,
00534                                           const DDS::OctetSeq& challenge1,
00535                                           const DDS::OctetSeq& dh1,
00536                                           const DDS::OctetSeq& challenge2,
00537                                           const DDS::OctetSeq& dh2,
00538                                           const DDS::OctetSeq& hash_c2,
00539                                           DDS::BinaryPropertySeq& dst)
00540 {
00541   DCPS::SequenceBackInsertIterator<DDS::BinaryPropertySeq> inserter(dst);
00542 
00543   {
00544     DDS::BinaryProperty_t p;
00545     p.name = "hash_c1";
00546     p.value = hash_c1;
00547     p.propagate = true;
00548     *inserter = p;
00549   }
00550 
00551   {
00552     DDS::BinaryProperty_t p;
00553     p.name = "challenge1";
00554     p.value = challenge1;
00555     p.propagate = true;
00556     *inserter = p;
00557   }
00558 
00559   {
00560     DDS::BinaryProperty_t p;
00561     p.name = "dh1";
00562     p.value = dh1;
00563     p.propagate = true;
00564     *inserter = p;
00565   }
00566 
00567   {
00568     DDS::BinaryProperty_t p;
00569     p.name = "challenge2";
00570     p.value = challenge2;
00571     p.propagate = true;
00572     *inserter = p;
00573   }
00574 
00575   {
00576     DDS::BinaryProperty_t p;
00577     p.name = "dh2";
00578     p.value = dh2;
00579     p.propagate = true;
00580     *inserter = p;
00581   }
00582 
00583   {
00584     DDS::BinaryProperty_t p;
00585     p.name = "hash_c2";
00586     p.value = hash_c2;
00587     p.propagate = true;
00588     *inserter = p;
00589   }
00590 }
00591 
00592 ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::begin_handshake_reply(
00593   ::DDS::Security::HandshakeHandle & handshake_handle,
00594   ::DDS::Security::HandshakeMessageToken & handshake_message_out,
00595   ::DDS::Security::IdentityHandle initiator_identity_handle,
00596   ::DDS::Security::IdentityHandle replier_identity_handle,
00597   const ::DDS::OctetSeq & serialized_local_participant_data,
00598   ::DDS::Security::SecurityException & ex)
00599 {
00600   using OpenDDS::Security::TokenWriter;
00601   using OpenDDS::Security::TokenReader;
00602 
00603   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00604 
00605   // Copy the "in" part of the inout param
00606   const DDS::Security::HandshakeMessageToken request_token = handshake_message_out;
00607   handshake_message_out = DDS::Security::HandshakeMessageToken();
00608 
00609   DDS::OctetSeq challenge1, challenge2, dh2, cperm, hash_c1, hash_c2;
00610 
00611   SSL::Certificate::unique_ptr remote_cert(new SSL::Certificate);
00612   SSL::DiffieHellman::unique_ptr diffie_hellman;
00613 
00614   const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED,
00615                                           Pending = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00616 
00617   if (serialized_local_participant_data.length() == 0) {
00618     set_security_error(ex, -1, 0, "No participant data provided");
00619     return Failure;
00620   }
00621 
00622   HandshakeDataPair handshake_data = make_handshake_pair(initiator_identity_handle, replier_identity_handle);
00623 
00624   if (! handshake_data.first) {
00625     set_security_error(ex, -1, 0, "Unknown local participant");
00626     return DDS::Security::VALIDATION_FAILED;
00627   }
00628 
00629   if (! handshake_data.second) {
00630     set_security_error(ex, -1, 0, "Unknown remote participant");
00631     return DDS::Security::VALIDATION_FAILED;
00632   }
00633 
00634   LocalParticipantData& local_data = *(handshake_data.first);
00635   RemoteParticipantData& remote_data = *(handshake_data.second);
00636 
00637   DDS::Security::HandshakeMessageToken message_data_in(request_token);
00638   TokenReader message_in(message_data_in);
00639   if (message_in.is_nil()) {
00640     set_security_error(ex, -1, 0, "Handshake_message_out is an inout param and must not be nil");
00641     return Failure;
00642 
00643   }
00644   challenge1 = message_in.get_bin_property_value("challenge1");
00645 
00646   TokenReader initiator_remote_auth_request(remote_data.remote_auth_request);
00647   if (! initiator_remote_auth_request.is_nil()) {
00648     const DDS::OctetSeq& future_challenge = initiator_remote_auth_request.get_bin_property_value("future_challenge");
00649 
00650     if (! challenges_match(challenge1, future_challenge)) {
00651       return Failure;
00652     }
00653   }
00654 
00655   const LocalAuthCredentialData& local_credential_data = *(local_data.credentials);
00656 
00657   const DDS::OctetSeq& cid = message_in.get_bin_property_value("c.id");
00658   if (cid.length() > 0) {
00659 
00660     remote_cert->deserialize(cid);
00661     if (X509_V_OK != remote_cert->validate(local_credential_data.get_ca_cert()))
00662     {
00663       set_security_error(ex, -1, 0, "Certificate validation failed");
00664       return Failure;
00665     }
00666 
00667   } else {
00668     set_security_error(ex, -1, 0, "Certificate validation failed due to empty 'c.id' property supplied");
00669     return Failure;
00670   }
00671 
00672   /* Validate participant_guid in c.pdata */
00673 
00674   const DDS::OctetSeq& cpdata = message_in.get_bin_property_value("c.pdata");
00675 
00676   std::vector<unsigned char> hash;
00677   if (0 != remote_cert->subject_name_digest(hash)) {
00678     set_security_error(ex, -1, 0, "Failed to generate subject-name digest from remote certificate.");
00679     return Failure;
00680   }
00681 
00682   if (! validate_topic_data_guid(cpdata, hash, ex)) {
00683     return Failure;
00684   }
00685 
00686   cperm = message_in.get_bin_property_value("c.perm");
00687 
00688   const DDS::OctetSeq& dh_algo = message_in.get_bin_property_value("c.kagree_algo");
00689   diffie_hellman.reset(SSL::DiffieHellman::factory(dh_algo));
00690 
00691   /* Compute hash_c1 and store for later */
00692 
00693   {
00694     CredentialHash hash(*remote_cert,
00695                         *diffie_hellman,
00696                         cpdata,
00697                         cperm);
00698     int err = hash(hash_c1);
00699     if (err) {
00700       set_security_error(ex, -1, 0, "Failed to compute hash_c1.");
00701       return Failure;
00702     }
00703   }
00704 
00705   /* Compute hash_c2 and store for later */
00706 
00707   {
00708     CredentialHash hash(local_credential_data.get_participant_cert(),
00709                         *diffie_hellman,
00710                         serialized_local_participant_data,
00711                         local_credential_data.get_access_permissions());
00712     int err = hash(hash_c2);
00713     if (err) {
00714       set_security_error(ex, -1, 0, "Failed to compute hash_c2.");
00715       return Failure;
00716     }
00717   }
00718 
00719   // TODO: Currently support for OCSP is optional in the security spec and
00720   // so it has been deferred to a post-beta release.
00721   // Add OCSP checks when "ocsp_status" property is given in message_in.
00722   // Most of this logic would probably be placed in the Certificate directly
00723   // or an OCSP abstraction that the Certificate uses.
00724 
00725   const DDS::OctetSeq& dh1 = message_in.get_bin_property_value("dh1");
00726 
00727   TokenWriter message_out(handshake_message_out, build_class_id(Handshake_Reply_Class_Ext));
00728 
00729   message_out.add_bin_property("c.id", local_credential_data.get_participant_cert().original_bytes());
00730   message_out.add_bin_property("c.perm", local_credential_data.get_access_permissions());
00731   message_out.add_bin_property("c.pdata", serialized_local_participant_data);
00732   message_out.add_bin_property("c.dsign_algo", local_credential_data.get_participant_cert().dsign_algo());
00733   message_out.add_bin_property("c.kagree_algo", diffie_hellman->kagree_algo());
00734   message_out.add_bin_property("hash_c2", hash_c2);
00735 
00736   diffie_hellman->pub_key(dh2);
00737   message_out.add_bin_property("dh2", dh2);
00738   message_out.add_bin_property("hash_c1", hash_c1);
00739   message_out.add_bin_property("dh1", dh1);
00740   message_out.add_bin_property("challenge1", challenge1);
00741 
00742   TokenReader initiator_local_auth_request(remote_data.local_auth_request);
00743   if (! initiator_local_auth_request.is_nil()) {
00744     const DDS::OctetSeq& future_challenge = initiator_local_auth_request.get_bin_property_value("future_challenge");
00745     message_out.add_bin_property("challenge2", future_challenge);
00746     challenge2 = future_challenge;
00747 
00748   } else {
00749     int err = SSL::make_nonce_256(challenge2);
00750     if (! err) {
00751       message_out.add_bin_property("challenge2", challenge2);
00752 
00753     } else {
00754       set_security_error(ex, -1, 0, "SSL::make_nonce_256 failed.");
00755       return Failure;
00756     }
00757   }
00758 
00759   DDS::BinaryPropertySeq sign_these;
00760   make_reply_signature_sequence(hash_c2,
00761                                 challenge2,
00762                                 dh2,
00763                                 challenge1,
00764                                 dh1,
00765                                 hash_c1,
00766                                 sign_these);
00767 
00768   DDS::OctetSeq signature;
00769   SSL::sign_serialized(sign_these, local_credential_data.get_participant_private_key(), signature);
00770   message_out.add_bin_property("signature", signature);
00771 
00772   remote_data.replier_identity = replier_identity_handle;
00773   remote_data.initiator_identity = initiator_identity_handle;
00774   remote_data.state = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
00775   remote_data.diffie_hellman = DCPS::move(diffie_hellman);
00776   remote_data.certificate = DCPS::move(remote_cert);
00777   remote_data.c_perm = cperm;
00778   remote_data.reply = handshake_message_out;
00779   remote_data.request = request_token;
00780   remote_data.hash_c1 = hash_c1;
00781   remote_data.hash_c2 = hash_c2;
00782 
00783   handshake_handle = get_next_handle();
00784   {
00785     ACE_Guard<ACE_Thread_Mutex> guard(handshake_mutex_);
00786     handshake_data_[handshake_handle] = handshake_data;
00787   }
00788 
00789   return Pending;
00790 }
00791 
00792 ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_handshake(
00793   ::DDS::Security::HandshakeMessageToken & handshake_message_out,
00794   const ::DDS::Security::HandshakeMessageToken & handshake_message_in,
00795   ::DDS::Security::HandshakeHandle handshake_handle,
00796   ::DDS::Security::SecurityException & ex)
00797 {
00798   // - SecurityException is populated if VALIDATION_FAILED
00799   DDS::Security::ValidationResult_t result = DDS::Security::VALIDATION_OK;
00800 
00801   // Handle differently based on which direction this handshake is going
00802   std::string incoming_class_ext = get_extension(handshake_message_in.class_id);
00803 
00804   if (0 == Handshake_Reply_Class_Ext.compare(incoming_class_ext))
00805   {
00806     result = process_handshake_reply(handshake_message_out, handshake_message_in, handshake_handle, ex);
00807   }
00808   else if (0 == Handshake_Final_Class_Ext.compare(incoming_class_ext))
00809   {
00810     result = process_final_handshake(handshake_message_in, handshake_handle, ex);
00811   }
00812 
00813   return result;
00814 }
00815 
00816 ::DDS::Security::SharedSecretHandle* AuthenticationBuiltInImpl::get_shared_secret(
00817   ::DDS::Security::HandshakeHandle handshake_handle,
00818   ::DDS::Security::SecurityException & ex)
00819 {
00820   using namespace DDS::Security;
00821 
00822   SharedSecretHandle* result = 0;
00823 
00824   ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
00825 
00826   HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
00827   if (handshake_data.first && handshake_data.second) {
00828 
00829     ValidationResult_t state = handshake_data.second->state;
00830     if (state == VALIDATION_OK || state == VALIDATION_OK_FINAL_MESSAGE) {
00831       SharedSecretHandle_var handle = handshake_data.second->shared_secret;
00832       result = handle._retn();
00833 
00834     } else {
00835       set_security_error(ex, -1, 0, "Validation state must be either VALIDATION_OK or VALIDATION_OK_FINAL_MESSAGE");
00836     }
00837 
00838   } else {
00839     set_security_error(ex, -1, 0, "Unknown handshake handle");
00840   }
00841 
00842   return result;
00843 }
00844 
00845 ::CORBA::Boolean AuthenticationBuiltInImpl::get_authenticated_peer_credential_token(
00846   ::DDS::Security::AuthenticatedPeerCredentialToken & peer_credential_token,
00847   ::DDS::Security::HandshakeHandle handshake_handle,
00848   ::DDS::Security::SecurityException & ex)
00849 {
00850   using namespace DDS::Security;
00851   ::CORBA::Boolean result = false;
00852 
00853   ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
00854 
00855   HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
00856   if (handshake_data.first && handshake_data.second) {
00857     ValidationResult_t state = handshake_data.second->state;
00858     if (state == VALIDATION_OK || state == VALIDATION_OK_FINAL_MESSAGE) {
00859       OpenDDS::Security::TokenWriter peer_token(peer_credential_token, Auth_Peer_Cred_Token_Class_Id);
00860 
00861       DDS::BinaryPropertySeq& props = peer_credential_token.binary_properties;
00862       props.length(2);
00863 
00864       DDS::BinaryProperty_t p1;
00865       p1.name = "c.id";
00866       p1.value = handshake_data.second->certificate->original_bytes();
00867       p1.propagate = true;
00868 
00869       DDS::BinaryProperty_t p2;
00870       p2.name = "c.perm";
00871       p2.value = handshake_data.second->c_perm;
00872       p2.propagate = true;
00873 
00874       props[0] = p1;
00875       props[1] = p2;
00876 
00877       result = true;
00878 
00879     } else {
00880       set_security_error(ex, -1, 0, "Validation state must be either VALIDATION_OK or VALIDATION_OK_FINAL_MESSAGE");
00881     }
00882 
00883   } else {
00884     set_security_error(ex, -1, 0, "Unknown handshake handle");
00885   }
00886 
00887   return result;
00888 }
00889 
00890 ::CORBA::Boolean AuthenticationBuiltInImpl::set_listener(
00891   ::DDS::Security::AuthenticationListener_ptr listener,
00892   ::DDS::Security::SecurityException & ex)
00893 {
00894   ::CORBA::Boolean results = false;
00895 
00896   if (NULL == listener) {
00897     set_security_error(ex, -1, 0, "Null listener provided");
00898   } else {
00899     results = true;
00900     listener_ptr_ = listener;
00901   }
00902   return results;
00903 }
00904 
00905 ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_token(
00906   const ::DDS::Security::IdentityToken & token,
00907   ::DDS::Security::SecurityException & ex)
00908 {
00909   // Nothing to do here yet
00910   ACE_UNUSED_ARG(token);
00911   ACE_UNUSED_ARG(ex);
00912   return true;
00913 }
00914 
00915 
00916 ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_status_token(
00917   const ::DDS::Security::IdentityStatusToken & token,
00918   ::DDS::Security::SecurityException & ex)
00919 {
00920   // Nothing to do here yet
00921   ACE_UNUSED_ARG(token);
00922   ACE_UNUSED_ARG(ex);
00923   return true;
00924 }
00925 
00926 
00927 ::CORBA::Boolean AuthenticationBuiltInImpl::return_authenticated_peer_credential_token(
00928   const ::DDS::Security::AuthenticatedPeerCredentialToken & peer_credential_token,
00929   ::DDS::Security::SecurityException & ex)
00930 {
00931   // Nothing to do here yet
00932   ACE_UNUSED_ARG(peer_credential_token);
00933   ACE_UNUSED_ARG(ex);
00934   return true;
00935 }
00936 
00937 ::CORBA::Boolean AuthenticationBuiltInImpl::return_handshake_handle(
00938   ::DDS::Security::HandshakeHandle handshake_handle,
00939   ::DDS::Security::SecurityException & ex)
00940 {
00941   ACE_Guard<ACE_Thread_Mutex> guard(handshake_mutex_);
00942 
00943   HandshakeDataMap::iterator found = handshake_data_.find(handshake_handle);
00944   if (found != handshake_data_.end()) {
00945     handshake_data_.erase(found);
00946     return true;
00947   }
00948 
00949   set_security_error(ex, -1, 0, "Handshake handle not recognized");
00950   return false;
00951 }
00952 
00953 ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_handle(
00954   ::DDS::Security::IdentityHandle identity_handle,
00955   ::DDS::Security::SecurityException & ex)
00956 {
00957   ACE_Guard<ACE_Thread_Mutex> guard(identity_mutex_);
00958 
00959   LocalParticipantMap::iterator local = local_participants_.find(identity_handle);
00960   if (local != local_participants_.end()) {
00961     local_participants_.erase(local);
00962     return true;
00963   }
00964 
00965   local = std::find_if(local_participants_.begin(), local_participants_.end(),
00966                        local_has_remote_handle(identity_handle));
00967 
00968   if (local != local_participants_.end()) {
00969     local->second->validated_remotes.erase(identity_handle);
00970     return true;
00971   }
00972 
00973   set_security_error(ex, -1, 0, "Identity handle not recognized");
00974   return false;
00975 }
00976 
00977 ::CORBA::Boolean AuthenticationBuiltInImpl::return_sharedsecret_handle(
00978   ::DDS::Security::SharedSecretHandle* sharedsecret_handle,
00979   ::DDS::Security::SecurityException & ex)
00980 {
00981   // Nothing to do here in the stub version
00982   ACE_UNUSED_ARG(sharedsecret_handle);
00983   ACE_UNUSED_ARG(ex);
00984   return true;
00985 }
00986 
00987 
00988 DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_handshake_reply(
00989   DDS::Security::HandshakeMessageToken & handshake_message_out,
00990   const DDS::Security::HandshakeMessageToken & handshake_message_in,
00991   DDS::Security::HandshakeHandle handshake_handle,
00992   DDS::Security::SecurityException & ex)
00993 {
00994 
00995   ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
00996   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
00997 
00998   DDS::OctetSeq challenge1, hash_c2;
00999   SSL::Certificate::unique_ptr remote_cert(new SSL::Certificate);
01000 
01001   const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED;
01002   const DDS::Security::ValidationResult_t FinalMessage = DDS::Security::VALIDATION_OK_FINAL_MESSAGE;
01003 
01004   HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
01005   if (!handshake_data.first || !handshake_data.second) {
01006     set_security_error(ex, -1, 0, "Unknown handshake handle");
01007     return Failure;
01008   }
01009 
01010   LocalParticipantData& local_data = *(handshake_data.first);
01011   RemoteParticipantData& remote_data = *(handshake_data.second);
01012 
01013   if (remote_data.state != DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE) {
01014     set_security_error(ex, -1, 0, "Handshake state is not valid");
01015     return Failure;
01016   }
01017 
01018   TokenReader message_in(handshake_message_in);
01019   if (message_in.is_nil()) {
01020     set_security_error(ex, -1, 0, "Handshake_message_in must not be nil");
01021     return Failure;
01022   }
01023 
01024   const DDS::OctetSeq& challenge2 = message_in.get_bin_property_value("challenge2");
01025 
01026   TokenReader auth_wrapper(remote_data.remote_auth_request);
01027   if (! auth_wrapper.is_nil()) {
01028     const DDS::OctetSeq& future_challenge = auth_wrapper.get_bin_property_value("future_challenge");
01029 
01030     if (! challenges_match(challenge2, future_challenge)) {
01031       set_security_error(ex, -1, 0, "challenge2 does not match future_challenge");
01032       return Failure;
01033     }
01034   }
01035 
01036   const LocalAuthCredentialData& local_credential_data = *(local_data.credentials);
01037 
01038   const DDS::OctetSeq& cid = message_in.get_bin_property_value("c.id");
01039   if (cid.length() > 0) {
01040 
01041       remote_cert->deserialize(cid);
01042 
01043     if (X509_V_OK != remote_cert->validate(local_credential_data.get_ca_cert()))
01044     {
01045       set_security_error(ex, -1, 0, "Certificate validation failed");
01046       return Failure;
01047     }
01048 
01049   } else {
01050     set_security_error(ex, -1, 0, "Certificate validation failed due to empty 'c.id' property supplied");
01051     return Failure;
01052   }
01053 
01054   /* Check that challenge1 on message_in matches the one sent in HandshakeRequestMessageToken */
01055 
01056   TokenReader handshake_request_token(remote_data.request);
01057   if (handshake_request_token.is_nil()) {
01058     set_security_error(ex, -1, 0, "Handshake-request-token is nil");
01059     return Failure;
01060 
01061   } else {
01062     challenge1 = handshake_request_token.get_bin_property_value("challenge1");
01063     const DDS::OctetSeq& challenge1_reply =  message_in.get_bin_property_value("challenge1");
01064 
01065     if (! challenges_match(challenge1, challenge1_reply)) {
01066       set_security_error(ex, -1, 0, "handshake-request challenge1 value does not match local challenge1");
01067       return Failure;
01068     }
01069   }
01070 
01071   /* Validate participant_guid in c.pdata */
01072 
01073   const DDS::OctetSeq& cpdata = message_in.get_bin_property_value("c.pdata");
01074 
01075   std::vector<unsigned char> hash;
01076   if (0 != remote_cert->subject_name_digest(hash)) {
01077     set_security_error(ex, -1, 0, "Failed to generate subject-name digest from remote certificate.");
01078     return Failure;
01079   }
01080 
01081   if (! validate_topic_data_guid(cpdata, hash, ex)) {
01082     return Failure;
01083   }
01084 
01085   /* Compute/Store the Diffie-Hellman shared-secret */
01086 
01087   const DDS::OctetSeq& dh2 = message_in.get_bin_property_value("dh2");
01088   if (0 != remote_data.diffie_hellman->gen_shared_secret(dh2)) {
01089     set_security_error(ex, -1, 0, "Failed to generate shared secret from dh1 and dh2");
01090     return Failure;
01091   }
01092 
01093   const DDS::OctetSeq& cperm = message_in.get_bin_property_value("c.perm");
01094 
01095   /* Compute hash_c2 and store for later (hash_c1 was already computed in request) */
01096 
01097   {
01098     CredentialHash hash(*remote_cert,
01099                         *remote_data.diffie_hellman,
01100                         cpdata,
01101                         cperm);
01102     int err = hash(hash_c2);
01103     if (err) {
01104       set_security_error(ex, -1, 0, "Computing hash_c2 failed");
01105       return Failure;
01106     }
01107   }
01108 
01109   /* Validate Signature field */
01110   const DDS::OctetSeq& dh1 = handshake_request_token.get_bin_property_value("dh1");
01111 
01112   DDS::BinaryPropertySeq verify_these;
01113   make_reply_signature_sequence(hash_c2,
01114                                 challenge2,
01115                                 dh2,
01116                                 challenge1,
01117                                 dh1,
01118                                 remote_data.hash_c1,
01119                                 verify_these);
01120 
01121   const DDS::OctetSeq& remote_signature = message_in.get_bin_property_value("signature");
01122 
01123   int err = SSL::verify_serialized(verify_these, *remote_cert, remote_signature);
01124   if (err) {
01125     set_security_error(ex, -1, 0, "Remote 'signature' field failed signature verification");
01126     return Failure;
01127   }
01128 
01129   OpenDDS::Security::TokenWriter final_msg(handshake_message_out, build_class_id(Handshake_Final_Class_Ext));
01130 
01131   final_msg.add_bin_property("hash_c1", remote_data.hash_c1);
01132   final_msg.add_bin_property("hash_c2", hash_c2);
01133   final_msg.add_bin_property("dh1", dh1);
01134   final_msg.add_bin_property("dh2", dh2);
01135   final_msg.add_bin_property("challenge1", challenge1);
01136   final_msg.add_bin_property("challenge2", challenge2);
01137 
01138   DDS::BinaryPropertySeq sign_these;
01139   make_final_signature_sequence(remote_data.hash_c1,
01140                                 challenge1,
01141                                 dh1,
01142                                 challenge2,
01143                                 dh2,
01144                                 hash_c2,
01145                                 sign_these);
01146 
01147   DDS::OctetSeq tmp;
01148   SSL::sign_serialized(sign_these, local_credential_data.get_participant_private_key(), tmp);
01149   final_msg.add_bin_property("signature", tmp);
01150 
01151   remote_data.certificate = DCPS::move(remote_cert);
01152   remote_data.state = FinalMessage;
01153   remote_data.c_perm = message_in.get_bin_property_value("c.perm");
01154   remote_data.hash_c2 = hash_c2;
01155   remote_data.shared_secret = new SharedSecret(challenge1,
01156                                                challenge2,
01157                                                remote_data.diffie_hellman->get_shared_secret());
01158   return FinalMessage;
01159 }
01160 
01161 bool challenges_match(const DDS::OctetSeq& c1, const DDS::OctetSeq& c2)
01162 {
01163   if ((c1.length()) < 1 || (c2.length() < 1)) {
01164     return false;
01165   }
01166   if (c1.length() != c2.length()) {
01167     return false;
01168   }
01169 
01170   if (0 != std::memcmp(c1.get_buffer(), c2.get_buffer(), c2.length())) {
01171     return false;
01172   }
01173 
01174   return true;
01175 }
01176 
01177 DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_final_handshake(
01178   const DDS::Security::HandshakeMessageToken & handshake_message_in, /* Final message token */
01179   DDS::Security::HandshakeHandle handshake_handle,
01180   DDS::Security::SecurityException & ex)
01181 {
01182   const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED;
01183   const DDS::Security::ValidationResult_t ValidationOkay = DDS::Security::VALIDATION_OK;
01184 
01185   ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
01186   ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
01187 
01188   HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
01189   if (!handshake_data.first || !handshake_data.second) {
01190     set_security_error(ex, -1, 0, "Unknown handshake handle");
01191     return Failure;
01192   }
01193 
01194   RemoteParticipantData& remote_data = *(handshake_data.second);
01195 
01196   if (remote_data.state != DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE) {
01197     set_security_error(ex, -1, 0, "Handshake state is not valid");
01198     return Failure;
01199   }
01200 
01201   /* Check challenge1 and challenge2 match what was sent with the reply-message-token */
01202 
01203   TokenReader handshake_final_token(handshake_message_in);
01204   if (handshake_final_token.is_nil()) {
01205     set_security_error(ex, -1, 0, "Handshake-final-token is nil");
01206     return Failure;
01207   }
01208 
01209   TokenReader handshake_reply_token(remote_data.reply);
01210   if (handshake_reply_token.is_nil()) {
01211     set_security_error(ex, -1, 0, "Handshake-reply-token is nil");
01212     return Failure;
01213   }
01214 
01215   /* Per the spec, dh1 is optional in all _but_ the request token so it's grabbed from the request */
01216   TokenReader handshake_request_token(remote_data.request);
01217   if (handshake_reply_token.is_nil()) {
01218     set_security_error(ex, -1, 0, "Handshake-reply-token is nil");
01219     return Failure;
01220   }
01221 
01222   const DDS::OctetSeq& dh1 = handshake_request_token.get_bin_property_value("dh1");
01223   const DDS::OctetSeq& dh2 = handshake_reply_token.get_bin_property_value("dh2");
01224 
01225   const DDS::OctetSeq& challenge1_reply = handshake_reply_token.get_bin_property_value("challenge1");
01226   const DDS::OctetSeq& challenge2_reply = handshake_reply_token.get_bin_property_value("challenge2");
01227 
01228   const DDS::OctetSeq& challenge1_final = handshake_final_token.get_bin_property_value("challenge1");
01229   const DDS::OctetSeq& challenge2_final = handshake_final_token.get_bin_property_value("challenge2");
01230 
01231   if (! challenges_match(challenge1_reply, challenge1_final) || ! challenges_match(challenge2_reply, challenge2_final)) {
01232       return Failure;
01233   }
01234 
01235   /* Validate Signature field */
01236 
01237   const SSL::Certificate::unique_ptr& remote_cert = remote_data.certificate;
01238 
01239   DDS::BinaryPropertySeq verify_these;
01240   make_final_signature_sequence(remote_data.hash_c1,
01241                                 challenge1_reply,
01242                                 dh1,
01243                                 challenge2_reply,
01244                                 dh2,
01245                                 remote_data.hash_c2,
01246                                 verify_these);
01247 
01248   const DDS::OctetSeq& remote_signature = handshake_final_token.get_bin_property_value("signature");
01249 
01250   int err = SSL::verify_serialized(verify_these, *remote_cert, remote_signature);
01251   if (err) {
01252     set_security_error(ex, -1, 0, "Remote 'signature' field failed signature verification");
01253     return Failure;
01254   }
01255 
01256   /* Compute/Store the Diffie-Hellman shared-secret */
01257 
01258   if (0 != remote_data.diffie_hellman->gen_shared_secret(dh1)) {
01259     set_security_error(ex, -1, 0, "Failed to generate shared secret from dh2 and dh1");
01260     return Failure;
01261   }
01262 
01263   remote_data.state = DDS::Security::VALIDATION_OK;
01264   remote_data.shared_secret = new SharedSecret(challenge1_reply,
01265                                                  challenge2_reply,
01266                                                  remote_data.diffie_hellman->get_shared_secret());
01267 
01268   return ValidationOkay;
01269 }
01270 
01271 AuthenticationBuiltInImpl::LocalParticipantData::shared_ptr
01272 AuthenticationBuiltInImpl::get_local_participant(DDS::Security::IdentityHandle handle)
01273 {
01274   LocalParticipantMap::iterator found = local_participants_.find(handle);
01275   if (found != local_participants_.end()) {
01276     return found->second;
01277   }
01278 
01279   return LocalParticipantData::shared_ptr();
01280 }
01281 
01282 AuthenticationBuiltInImpl::HandshakeDataPair
01283 AuthenticationBuiltInImpl::get_handshake_data(DDS::Security::HandshakeHandle handle)
01284 {
01285   HandshakeDataMap::iterator found = handshake_data_.find(handle);
01286   if (found != handshake_data_.end()) {
01287     return found->second;
01288   }
01289 
01290   return HandshakeDataPair();
01291 }
01292 
01293 AuthenticationBuiltInImpl::HandshakeDataPair
01294 AuthenticationBuiltInImpl::make_handshake_pair(DDS::Security::IdentityHandle h1,
01295                                                DDS::Security::IdentityHandle h2)
01296 {
01297   DDS::Security::IdentityHandle other = DDS::HANDLE_NIL;
01298 
01299   LocalParticipantMap::iterator found_local = local_participants_.find(h1);
01300   if (found_local != local_participants_.end()) {
01301     other = h2;
01302 
01303   } else {
01304     found_local = local_participants_.find(h2);
01305     if (found_local != local_participants_.end()) {
01306       other = h1;
01307 
01308     } else {
01309       return HandshakeDataPair();
01310     }
01311   }
01312 
01313   RemoteParticipantMap::iterator found_remote = found_local->second->validated_remotes.find(other);
01314   if (found_remote != found_local->second->validated_remotes.end()) {
01315     return std::make_pair(found_local->second, found_remote->second);
01316   }
01317 
01318   return HandshakeDataPair();
01319 }
01320 
01321 bool AuthenticationBuiltInImpl::is_handshake_initiator(const OpenDDS::DCPS::GUID_t& local, const OpenDDS::DCPS::GUID_t& remote)
01322 {
01323   const unsigned char* local_ = reinterpret_cast<const unsigned char*>(&local);
01324   const unsigned char* remote_ = reinterpret_cast<const unsigned char*>(&remote);
01325 
01326   /* if remote > local, pending request; else pending handshake message */
01327   return std::lexicographical_compare(local_, local_ + sizeof(local),
01328                                       remote_, remote_ + sizeof(remote));
01329 
01330 }
01331 
01332 bool AuthenticationBuiltInImpl::check_class_versions(const char* remote_class_id)
01333 {
01334   if (NULL == remote_class_id) {
01335     return false;
01336     }
01337   bool class_matches = false;
01338 
01339   // Slow, but this is just for the stub
01340   std::string class_id_str(remote_class_id);
01341 
01342   // Class name is the text prior to the final ':'
01343   size_t colon_pos = class_id_str.find_last_of(':');
01344   if (std::string::npos != colon_pos && colon_pos > 0) {
01345     // Compare the class name vs the expected class name
01346     std::string remote_class_name  = class_id_str.substr(0, colon_pos);
01347     if (0 == Auth_Plugin_Name.compare(remote_class_name)) {
01348       // Major version is the text between the final : and a  .
01349       size_t major_start = colon_pos + 1;
01350       size_t period_pos = class_id_str.find_first_of('.', major_start);
01351       if (std::string::npos != period_pos && period_pos > major_start) {
01352         std::string major_version = class_id_str.substr(major_start, period_pos - major_start);
01353         if (0 == Auth_Plugin_Major_Version.compare(major_version)) {
01354           class_matches = true;
01355         }
01356       }
01357     }
01358   }
01359 
01360   return class_matches;
01361 }
01362 
01363 std::string AuthenticationBuiltInImpl::build_class_id(const std::string& message_ext)
01364 {
01365   std::stringstream class_id_stream;
01366   class_id_stream << Auth_Plugin_Name
01367     << ":" << Auth_Plugin_Major_Version
01368     << "." << Auth_Plugin_Minor_Version
01369     << "+" << message_ext;
01370 
01371   return class_id_stream.str();
01372 }
01373 
01374 std::string AuthenticationBuiltInImpl::get_extension(const char* class_id)
01375 {
01376   std::string ext_string("");
01377 
01378   std::string class_id_str(class_id);
01379   size_t extension_delim_pos = class_id_str.find_last_of('+');
01380   if (extension_delim_pos != std::string::npos) {
01381     size_t start_ext_pos = extension_delim_pos + 1;
01382     if (start_ext_pos < class_id_str.length()) {
01383     ext_string = class_id_str.substr(start_ext_pos);
01384     }
01385   }
01386 
01387   return ext_string;
01388 }
01389 
01390 CORBA::Long AuthenticationBuiltInImpl::get_next_handle()
01391 {
01392   ACE_Guard<ACE_Thread_Mutex> guard(handle_mutex_);
01393   return CommonUtilities::increment_handle(next_handle_);
01394 }
01395 
01396 } // namespace Security
01397 } // namespace OpenDDS
01398 
01399 OPENDDS_END_VERSIONED_NAMESPACE_DECL
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1