Line data Source code
1 : /*
2 : *
3 : *
4 : * Distributed under the OpenDDS License.
5 : * See: http://www.opendds.org/license.html
6 : */
7 :
8 : #include "AuthenticationBuiltInImpl.h"
9 :
10 : #include "CommonUtilities.h"
11 : #include "TokenReader.h"
12 : #include "TokenWriter.h"
13 : #include "SSL/Utils.h"
14 :
15 : #include "dds/DCPS/GuidUtils.h"
16 : #include "dds/DCPS/LocalObject.h"
17 : #include "dds/DCPS/Serializer.h"
18 :
19 : #include "dds/DCPS/RTPS/RtpsCoreC.h"
20 : #include "dds/DCPS/RTPS/RtpsCoreTypeSupportImpl.h"
21 :
22 : #include "ace/config-macros.h"
23 : #include "ace/Guard_T.h"
24 :
25 : #include <sstream>
26 : #include <vector>
27 : #include <algorithm>
28 : #include <cstdio>
29 :
30 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
31 :
32 : namespace OpenDDS {
33 : namespace Security {
34 :
35 : using CommonUtilities::set_security_error;
36 :
37 : static bool challenges_match(const DDS::OctetSeq& c1, const DDS::OctetSeq& c2);
38 :
39 : static void extract_participant_guid_from_cpdata(const DDS::OctetSeq& cpdata, DCPS::GUID_t& dst);
40 :
41 : static bool validate_topic_data_guid(const DDS::OctetSeq& cpdata,
42 : const std::vector<unsigned char>& subject_name_hash,
43 : DDS::Security::SecurityException& ex);
44 :
45 : const std::string Auth_Plugin_Name("DDS:Auth:PKI-DH");
46 : const std::string Auth_Plugin_Major_Version("1");
47 : const std::string Auth_Plugin_Minor_Version("0");
48 :
49 : const std::string Auth_Request_Class_Ext("AuthReq");
50 : const std::string Handshake_Request_Class_Ext("Req");
51 : const std::string Handshake_Reply_Class_Ext("Reply");
52 : const std::string Handshake_Final_Class_Ext("Final");
53 :
54 : const char* AuthenticationBuiltInImpl::PROPERTY_HANDSHAKE_DEBUG = "opendds.sec.auth.handshake_debug";
55 :
56 : struct SharedSecret : DCPS::LocalObject<DDS::Security::SharedSecretHandle> {
57 :
58 10 : SharedSecret(DDS::OctetSeq challenge1,
59 : DDS::OctetSeq challenge2,
60 : DDS::OctetSeq sharedSecret)
61 20 : : challenge1_(challenge1)
62 10 : , challenge2_(challenge2)
63 20 : , shared_secret_(sharedSecret)
64 10 : {}
65 :
66 0 : DDS::OctetSeq* challenge1() { return new DDS::OctetSeq(challenge1_); }
67 0 : DDS::OctetSeq* challenge2() { return new DDS::OctetSeq(challenge2_); }
68 2 : DDS::OctetSeq* sharedSecret() { return new DDS::OctetSeq(shared_secret_); }
69 :
70 : DDS::OctetSeq challenge1_, challenge2_, shared_secret_;
71 : };
72 :
73 32 : AuthenticationBuiltInImpl::AuthenticationBuiltInImpl()
74 32 : : listener_ptr_()
75 32 : , identity_mutex_()
76 32 : , handshake_mutex_()
77 32 : , handle_mutex_()
78 32 : , next_handle_(1)
79 : {
80 32 : }
81 :
82 32 : AuthenticationBuiltInImpl::~AuthenticationBuiltInImpl()
83 : {
84 32 : if (DCPS::security_debug.bookkeeping) {
85 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
86 : ACE_TEXT("AuthenticationBuiltInImpl::~AuthenticationBuiltInImpl local_participants_ %B handshake_data_ %B\n"),
87 : local_participants_.size(),
88 : handshake_data_.size()));
89 : }
90 32 : }
91 :
92 22 : ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::validate_local_identity(
93 : ::DDS::Security::IdentityHandle & local_identity_handle,
94 : ::OpenDDS::DCPS::GUID_t & adjusted_participant_guid,
95 : ::DDS::Security::DomainId_t /*domain_id*/,
96 : const ::DDS::DomainParticipantQos & participant_qos,
97 : const ::OpenDDS::DCPS::GUID_t & candidate_participant_guid,
98 : ::DDS::Security::SecurityException & ex)
99 : {
100 22 : DDS::Security::ValidationResult_t result = DDS::Security::VALIDATION_FAILED;
101 :
102 22 : LocalAuthCredentialData::shared_ptr credentials = DCPS::make_rch<LocalAuthCredentialData>();
103 22 : if (!credentials->load_credentials(participant_qos.property.value, ex)) {
104 0 : return result;
105 : }
106 :
107 22 : if (credentials->validate()) {
108 22 : if (candidate_participant_guid != DCPS::GUID_UNKNOWN) {
109 :
110 22 : int err = SSL::make_adjusted_guid(candidate_participant_guid,
111 : adjusted_participant_guid,
112 : credentials->get_participant_cert());
113 22 : if (!err) {
114 22 : local_identity_handle = get_next_handle();
115 :
116 22 : LocalParticipantData::shared_ptr local_participant = DCPS::make_rch<LocalParticipantData>();
117 22 : local_participant->participant_guid = adjusted_participant_guid;
118 22 : local_participant->credentials = credentials;
119 132 : for (unsigned i = 0; i < participant_qos.property.value.length(); ++i) {
120 220 : if (std::strcmp(PROPERTY_HANDSHAKE_DEBUG,
121 110 : participant_qos.property.value[i].name.in()) == 0) {
122 0 : local_participant->handshake_debug = true;
123 : }
124 : }
125 :
126 : {
127 22 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
128 22 : local_participants_[local_identity_handle] = local_participant;
129 :
130 22 : if (DCPS::security_debug.bookkeeping) {
131 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
132 : ACE_TEXT("AuthenticationBuiltInImpl::validate_local_identity local_participants_ (total %B)\n"),
133 : local_participants_.size()));
134 : }
135 22 : }
136 :
137 22 : result = DDS::Security::VALIDATION_OK;
138 :
139 22 : } else {
140 0 : set_security_error(ex, -1, 0, "SSL::make_adjusted_guid failed");
141 : }
142 :
143 : } else {
144 0 : set_security_error(ex, -1, 0, "GUID_UNKNOWN passed in for candidate_participant_guid");
145 : }
146 :
147 : } else {
148 0 : set_security_error(ex, -1, 0, "local-credential-data failed validation");
149 : }
150 :
151 22 : return result;
152 22 : }
153 :
154 21 : ::CORBA::Boolean AuthenticationBuiltInImpl::get_identity_token(
155 : ::DDS::Security::IdentityToken & identity_token,
156 : ::DDS::Security::IdentityHandle handle,
157 : ::DDS::Security::SecurityException & ex)
158 : {
159 21 : ::CORBA::Boolean status = false;
160 :
161 21 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
162 :
163 21 : LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
164 21 : if (local_data) {
165 21 : const LocalAuthCredentialData& local_credential_data = *(local_data->credentials);
166 :
167 21 : const SSL::Certificate& pcert = local_credential_data.get_participant_cert();
168 21 : const SSL::Certificate& cacert = local_credential_data.get_ca_cert();
169 :
170 21 : std::string tmp;
171 :
172 42 : OpenDDS::Security::TokenWriter identity_wrapper(identity_token, Identity_Status_Token_Class_Id);
173 :
174 21 : pcert.subject_name_to_str(tmp);
175 21 : identity_wrapper.add_property(dds_cert_sn, tmp.c_str());
176 21 : identity_wrapper.add_property(dds_cert_algo, pcert.keypair_algo());
177 :
178 21 : cacert.subject_name_to_str(tmp);
179 21 : identity_wrapper.add_property(dds_ca_sn, tmp.c_str());
180 21 : identity_wrapper.add_property(dds_ca_algo, cacert.keypair_algo());
181 :
182 21 : status = true;
183 :
184 21 : } else {
185 0 : set_security_error(ex, -1, 0, "Unknown Identity handle");
186 : }
187 21 : return status;
188 21 : }
189 :
190 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::get_identity_status_token(
191 : ::DDS::Security::IdentityStatusToken&,
192 : ::DDS::Security::IdentityHandle handle,
193 : ::DDS::Security::SecurityException & ex)
194 : {
195 0 : ::CORBA::Boolean status = false;
196 :
197 0 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
198 :
199 : // Populate a simple version of an IdentityStatusToken as long as the handle is known
200 0 : LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
201 0 : if (local_data) {
202 :
203 : // TODO: Pending AuthenticationListener support (see security spec. 8.3.2.2).
204 : // This routine will most likely populate the IdentityStatusToken with
205 : // useful data once this has been completed. For now it's a glorified no-op!
206 :
207 0 : status = true;
208 : } else {
209 0 : set_security_error(ex, -1, 0, "Unknown Identity handle");
210 : }
211 :
212 0 : return status;
213 0 : }
214 :
215 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::set_permissions_credential_and_token(
216 : ::DDS::Security::IdentityHandle handle,
217 : const ::DDS::Security::PermissionsCredentialToken & permissions_credential,
218 : const ::DDS::Security::PermissionsToken & permissions_token,
219 : ::DDS::Security::SecurityException & ex)
220 : {
221 : ACE_UNUSED_ARG(permissions_token);
222 :
223 0 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
224 :
225 0 : LocalParticipantData::shared_ptr local_data = get_local_participant(handle);
226 0 : if (! local_data) {
227 0 : set_security_error(ex, -1, 0, "Identity handle not recognized");
228 0 : return false;
229 : }
230 :
231 0 : return local_data->credentials->load_access_permissions(permissions_credential, ex);
232 0 : }
233 :
234 16 : ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::validate_remote_identity(
235 : ::DDS::Security::IdentityHandle & remote_identity_handle,
236 : ::DDS::Security::AuthRequestMessageToken & local_auth_request_token,
237 : const ::DDS::Security::AuthRequestMessageToken & remote_auth_request_token,
238 : ::DDS::Security::IdentityHandle local_identity_handle,
239 : const ::DDS::Security::IdentityToken & remote_identity_token,
240 : const ::OpenDDS::DCPS::GUID_t & remote_participant_guid,
241 : ::DDS::Security::SecurityException & ex)
242 : {
243 16 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
244 :
245 16 : LocalParticipantData::shared_ptr local_data = get_local_participant(local_identity_handle);
246 :
247 16 : if (!local_data) {
248 0 : set_security_error(ex, -1, 0, "Local participant ID not found");
249 0 : return DDS::Security::VALIDATION_FAILED;
250 : }
251 :
252 16 : if (!check_class_versions(remote_identity_token.class_id)) {
253 0 : set_security_error(ex, -1, 0, "Remote class ID is not compatible");
254 0 : return DDS::Security::VALIDATION_FAILED;
255 : }
256 :
257 : // Make sure that a remote_participant_guid has not already been assigned a
258 : // remote-identity-handle before creating a new one.
259 16 : RemoteParticipantMap::iterator begin = local_data->validated_remotes.begin(),
260 16 : end = local_data->validated_remotes.end(),
261 16 : found = std::find_if(begin, end,
262 : was_guid_validated(remote_participant_guid));
263 :
264 16 : if (found == end) {
265 : // Generate local token.
266 16 : DDS::OctetSeq nonce;
267 16 : int err = SSL::make_nonce_256(nonce);
268 16 : if (err) {
269 0 : set_security_error(ex, -1, 0, "Failed to generate 256-bit nonce value for future_challenge property");
270 0 : return DDS::Security::VALIDATION_FAILED;
271 : }
272 :
273 16 : TokenWriter auth_req_wrapper(local_auth_request_token, build_class_id(Auth_Request_Class_Ext));
274 16 : auth_req_wrapper.add_bin_property("future_challenge", nonce);
275 :
276 : // Retain all of the data needed for a handshake with the remote participant
277 16 : RemoteParticipantData::shared_ptr remote_participant = DCPS::make_rch<RemoteParticipantData>();
278 16 : remote_participant->participant_guid = remote_participant_guid;
279 16 : remote_participant->local_participant = local_identity_handle;
280 16 : remote_participant->local_auth_request = local_auth_request_token;
281 :
282 16 : remote_identity_handle = get_next_handle();
283 16 : found = local_data->validated_remotes.insert(std::make_pair(remote_identity_handle, remote_participant)).first;
284 :
285 16 : if (DCPS::security_debug.bookkeeping) {
286 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
287 : ACE_TEXT("AuthenticationBuiltInImpl::validate_remote_identity validated_remotes (total %B)\n"),
288 : local_data->validated_remotes.size()));
289 : }
290 16 : }
291 :
292 : // Update the remote token.
293 16 : found->second->remote_auth_request = remote_auth_request_token;
294 :
295 : // Set return values.
296 16 : remote_identity_handle = found->first;
297 :
298 : // Don't need to send the local token if we have a remote token.
299 16 : TokenReader remote_request(remote_auth_request_token);
300 16 : if (remote_request.is_nil()) {
301 10 : local_auth_request_token = found->second->local_auth_request;
302 : } else {
303 6 : local_auth_request_token = DDS::Security::Token();
304 : }
305 :
306 16 : if (is_handshake_initiator(local_data->participant_guid, remote_participant_guid)) {
307 9 : return DDS::Security::VALIDATION_PENDING_HANDSHAKE_REQUEST;
308 : } else {
309 7 : return DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
310 : }
311 16 : }
312 :
313 7 : ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::begin_handshake_request(
314 : ::DDS::Security::HandshakeHandle & handshake_handle,
315 : ::DDS::Security::HandshakeMessageToken & handshake_message,
316 : ::DDS::Security::IdentityHandle initiator_identity_handle,
317 : ::DDS::Security::IdentityHandle replier_identity_handle,
318 : const ::DDS::OctetSeq & serialized_local_participant_data,
319 : ::DDS::Security::SecurityException & ex)
320 : {
321 7 : if (serialized_local_participant_data.length() == 0) {
322 0 : set_security_error(ex, -1, 0, "No participant data provided");
323 0 : return DDS::Security::VALIDATION_FAILED;
324 : }
325 :
326 7 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
327 :
328 7 : HandshakeDataPair handshake_data = make_handshake_pair(initiator_identity_handle, replier_identity_handle);
329 :
330 7 : if (! handshake_data.first) {
331 0 : set_security_error(ex, -1, 0, "Unknown local participant");
332 0 : return DDS::Security::VALIDATION_FAILED;
333 : }
334 :
335 7 : if (! handshake_data.second) {
336 0 : set_security_error(ex, -1, 0, "Unknown remote participant");
337 0 : return DDS::Security::VALIDATION_FAILED;
338 : }
339 :
340 7 : const LocalParticipantData& local_data = *handshake_data.first;
341 7 : RemoteParticipantData& remote_data = *handshake_data.second;
342 :
343 7 : const LocalAuthCredentialData& local_credential_data = *local_data.credentials;
344 :
345 7 : SSL::DiffieHellman::unique_ptr diffie_hellman(new SSL::DiffieHellman(new SSL::ECDH_PRIME_256_V1_CEUM));
346 :
347 7 : OpenDDS::Security::TokenWriter message_out(handshake_message, build_class_id(Handshake_Request_Class_Ext));
348 :
349 : // Compute hash_c1 and store for later
350 :
351 7 : DDS::OctetSeq hash_c1;
352 :
353 : {
354 : CredentialHash hash(local_credential_data.get_participant_cert(),
355 7 : *diffie_hellman,
356 : serialized_local_participant_data,
357 14 : local_credential_data.get_access_permissions());
358 :
359 7 : int err = hash(hash_c1);
360 7 : if (err) {
361 0 : set_security_error(ex, -1, 0, "Failed to generate credential-hash 'hash_c1'");
362 0 : return DDS::Security::VALIDATION_FAILED;
363 : }
364 : }
365 :
366 7 : message_out.add_bin_property("c.id", local_credential_data.get_participant_cert().original_bytes());
367 7 : message_out.add_bin_property("c.perm", local_credential_data.get_access_permissions());
368 7 : message_out.add_bin_property("c.pdata", serialized_local_participant_data);
369 7 : message_out.add_bin_property("c.dsign_algo", local_credential_data.get_participant_cert().dsign_algo());
370 7 : message_out.add_bin_property("c.kagree_algo", diffie_hellman->kagree_algo());
371 7 : if (local_data.handshake_debug) {
372 0 : message_out.add_bin_property("hash_c1", hash_c1);
373 : }
374 :
375 7 : DDS::OctetSeq dhpub;
376 7 : diffie_hellman->pub_key(dhpub);
377 7 : message_out.add_bin_property("dh1", dhpub);
378 :
379 7 : OpenDDS::Security::TokenReader auth_wrapper(remote_data.local_auth_request);
380 7 : if (auth_wrapper.is_nil()) {
381 0 : DDS::OctetSeq nonce;
382 0 : int err = SSL::make_nonce_256(nonce);
383 0 : if (! err) {
384 0 : message_out.add_bin_property("challenge1", nonce);
385 :
386 : } else {
387 0 : set_security_error(ex, -1, 0, "Failed to generate 256-bit nonce value for challenge1 property");
388 0 : return DDS::Security::VALIDATION_FAILED;
389 : }
390 :
391 0 : } else {
392 7 : const DDS::OctetSeq& challenge_data = auth_wrapper.get_bin_property_value("future_challenge");
393 7 : message_out.add_bin_property("challenge1", challenge_data);
394 : }
395 :
396 7 : remote_data.initiator_identity = initiator_identity_handle;
397 7 : remote_data.replier_identity = replier_identity_handle;
398 7 : remote_data.state = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
399 7 : remote_data.request = handshake_message;
400 7 : remote_data.reply = DDS::Security::Token();
401 7 : remote_data.diffie_hellman = DCPS::move(diffie_hellman);
402 7 : remote_data.hash_c1 = hash_c1;
403 :
404 7 : if (handshake_handle == DDS::HANDLE_NIL) {
405 7 : handshake_handle = get_next_handle();
406 : }
407 :
408 : {
409 7 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(handshake_mutex_);
410 7 : handshake_data_[handshake_handle] = handshake_data;
411 :
412 7 : if (DCPS::security_debug.bookkeeping) {
413 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
414 : ACE_TEXT("AuthenticationBuiltInImpl::begin_handshake_request handshake_data_ (total %B)\n"),
415 : handshake_data_.size()));
416 : }
417 7 : }
418 :
419 7 : return DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
420 7 : }
421 :
422 12 : void extract_participant_guid_from_cpdata(const DDS::OctetSeq& cpdata, DCPS::GUID_t& dst)
423 : {
424 12 : dst = DCPS::GUID_UNKNOWN;
425 :
426 12 : ACE_Message_Block buffer(reinterpret_cast<const char*>(cpdata.get_buffer()), cpdata.length());
427 12 : buffer.wr_ptr(cpdata.length());
428 : OpenDDS::DCPS::Serializer serializer(&buffer,
429 : DCPS::Encoding::KIND_XCDR1,
430 12 : DCPS::ENDIAN_BIG);
431 12 : RTPS::ParameterList params;
432 :
433 12 : if (serializer >> params) {
434 12 : for (unsigned int i = 0; i < params.length(); ++i) {
435 12 : const RTPS::Parameter& p = params[i];
436 :
437 12 : if (p._d() == RTPS::PID_PARTICIPANT_GUID) {
438 12 : dst = p.guid();
439 12 : break;
440 : }
441 : }
442 :
443 : } else {
444 0 : ACE_ERROR((LM_WARNING,
445 : ACE_TEXT("(%P|%t) WARNING: extract_participant_guid_from_cpdata, ")
446 : ACE_TEXT("failed to deserialize guid from cpdata.\n")));
447 : }
448 :
449 12 : }
450 :
451 12 : bool validate_topic_data_guid(const DDS::OctetSeq& cpdata,
452 : const std::vector<unsigned char>& subject_name_hash,
453 : DDS::Security::SecurityException& ex)
454 : {
455 12 : if (cpdata.length() > 5u) { /* Enough to withstand the hash-comparison below */
456 :
457 : DCPS::GUID_t remote_participant_guid;
458 12 : extract_participant_guid_from_cpdata(cpdata, remote_participant_guid);
459 :
460 12 : const DCPS::GuidPrefix_t& prefix = remote_participant_guid.guidPrefix;
461 :
462 : /* Make sure first bit is set */
463 :
464 12 : if ((prefix[0] & 0x80) != 0x80) {
465 0 : set_security_error(ex, -1, 0, "Malformed participant_guid in 'c.pdata'; First bit must be set.");
466 0 : return false;
467 : }
468 :
469 : /* Check the following 47 bits match the subject-hash */
470 :
471 : /* First byte needs to remove the manually-set first-bit before comparison */
472 12 : if ((prefix[0] & 0x7F) != SSL::offset_1bit(&subject_name_hash[0], 0)) {
473 0 : 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'");
474 0 : return false;
475 : }
476 72 : for (size_t i = 1; i <= 5u; ++i) { /* Compare remaining 5 bytes */
477 60 : 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 */
478 0 : 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'");
479 0 : return false;
480 : }
481 : }
482 :
483 : } else {
484 0 : set_security_error(ex, -1, 0, "Data missing in 'c.pdata'");
485 0 : return false;
486 : }
487 :
488 12 : return true;
489 : }
490 :
491 12 : static void make_reply_signature_sequence(const DDS::OctetSeq& hash_c2,
492 : const DDS::OctetSeq& challenge2,
493 : const DDS::OctetSeq& dh2,
494 : const DDS::OctetSeq& challenge1,
495 : const DDS::OctetSeq& dh1,
496 : const DDS::OctetSeq& hash_c1,
497 : DDS::BinaryPropertySeq& dst)
498 : {
499 12 : DCPS::SequenceBackInsertIterator<DDS::BinaryPropertySeq> inserter(dst);
500 :
501 : {
502 12 : DDS::BinaryProperty_t p;
503 12 : p.name = "hash_c2";
504 12 : p.value = hash_c2;
505 12 : p.propagate = true;
506 12 : *inserter = p;
507 12 : }
508 :
509 : {
510 12 : DDS::BinaryProperty_t p;
511 12 : p.name = "challenge2";
512 12 : p.value = challenge2;
513 12 : p.propagate = true;
514 12 : *inserter = p;
515 12 : }
516 :
517 : {
518 12 : DDS::BinaryProperty_t p;
519 12 : p.name = "dh2";
520 12 : p.value = dh2;
521 12 : p.propagate = true;
522 12 : *inserter = p;
523 12 : }
524 :
525 : {
526 12 : DDS::BinaryProperty_t p;
527 12 : p.name = "challenge1";
528 12 : p.value = challenge1;
529 12 : p.propagate = true;
530 12 : *inserter = p;
531 12 : }
532 :
533 : {
534 12 : DDS::BinaryProperty_t p;
535 12 : p.name = "dh1";
536 12 : p.value = dh1;
537 12 : p.propagate = true;
538 12 : *inserter = p;
539 12 : }
540 :
541 : {
542 12 : DDS::BinaryProperty_t p;
543 12 : p.name = "hash_c1";
544 12 : p.value = hash_c1;
545 12 : p.propagate = true;
546 12 : *inserter = p;
547 12 : }
548 12 : }
549 :
550 10 : static void make_final_signature_sequence(const DDS::OctetSeq& hash_c1,
551 : const DDS::OctetSeq& challenge1,
552 : const DDS::OctetSeq& dh1,
553 : const DDS::OctetSeq& challenge2,
554 : const DDS::OctetSeq& dh2,
555 : const DDS::OctetSeq& hash_c2,
556 : DDS::BinaryPropertySeq& dst)
557 : {
558 10 : DCPS::SequenceBackInsertIterator<DDS::BinaryPropertySeq> inserter(dst);
559 :
560 : {
561 10 : DDS::BinaryProperty_t p;
562 10 : p.name = "hash_c1";
563 10 : p.value = hash_c1;
564 10 : p.propagate = true;
565 10 : *inserter = p;
566 10 : }
567 :
568 : {
569 10 : DDS::BinaryProperty_t p;
570 10 : p.name = "challenge1";
571 10 : p.value = challenge1;
572 10 : p.propagate = true;
573 10 : *inserter = p;
574 10 : }
575 :
576 : {
577 10 : DDS::BinaryProperty_t p;
578 10 : p.name = "dh1";
579 10 : p.value = dh1;
580 10 : p.propagate = true;
581 10 : *inserter = p;
582 10 : }
583 :
584 : {
585 10 : DDS::BinaryProperty_t p;
586 10 : p.name = "challenge2";
587 10 : p.value = challenge2;
588 10 : p.propagate = true;
589 10 : *inserter = p;
590 10 : }
591 :
592 : {
593 10 : DDS::BinaryProperty_t p;
594 10 : p.name = "dh2";
595 10 : p.value = dh2;
596 10 : p.propagate = true;
597 10 : *inserter = p;
598 10 : }
599 :
600 : {
601 10 : DDS::BinaryProperty_t p;
602 10 : p.name = "hash_c2";
603 10 : p.value = hash_c2;
604 10 : p.propagate = true;
605 10 : *inserter = p;
606 10 : }
607 10 : }
608 :
609 7 : ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::begin_handshake_reply(
610 : ::DDS::Security::HandshakeHandle & handshake_handle,
611 : ::DDS::Security::HandshakeMessageToken & handshake_message_out,
612 : ::DDS::Security::IdentityHandle initiator_identity_handle,
613 : ::DDS::Security::IdentityHandle replier_identity_handle,
614 : const ::DDS::OctetSeq & serialized_local_participant_data,
615 : ::DDS::Security::SecurityException & ex)
616 : {
617 : using OpenDDS::Security::TokenWriter;
618 : using OpenDDS::Security::TokenReader;
619 :
620 7 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
621 :
622 : // Copy the "in" part of the inout param
623 7 : const DDS::Security::HandshakeMessageToken request_token = handshake_message_out;
624 7 : handshake_message_out = DDS::Security::HandshakeMessageToken();
625 :
626 7 : DDS::OctetSeq challenge1, challenge2, dh2, cperm, hash_c1, hash_c2;
627 :
628 7 : SSL::Certificate::unique_ptr remote_cert(new SSL::Certificate);
629 7 : SSL::DiffieHellman::unique_ptr diffie_hellman;
630 :
631 7 : const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED,
632 7 : Pending = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
633 :
634 7 : if (serialized_local_participant_data.length() == 0) {
635 0 : set_security_error(ex, -1, 0, "No participant data provided");
636 0 : return Failure;
637 : }
638 :
639 7 : HandshakeDataPair handshake_data = make_handshake_pair(initiator_identity_handle, replier_identity_handle);
640 :
641 7 : if (! handshake_data.first) {
642 0 : set_security_error(ex, -1, 0, "Unknown local participant");
643 0 : return Failure;
644 : }
645 :
646 7 : if (! handshake_data.second) {
647 0 : set_security_error(ex, -1, 0, "Unknown remote participant");
648 0 : return Failure;
649 : }
650 :
651 7 : const LocalParticipantData& local_data = *handshake_data.first;
652 7 : RemoteParticipantData& remote_data = *handshake_data.second;
653 :
654 7 : DDS::Security::HandshakeMessageToken message_data_in(request_token);
655 7 : TokenReader message_in(message_data_in);
656 7 : if (message_in.is_nil()) {
657 0 : set_security_error(ex, -1, 0, "Handshake_message_out is an inout param and must not be nil");
658 0 : return Failure;
659 :
660 : }
661 7 : challenge1 = message_in.get_bin_property_value("challenge1");
662 :
663 7 : TokenReader initiator_remote_auth_request(remote_data.remote_auth_request);
664 7 : if (! initiator_remote_auth_request.is_nil()) {
665 6 : const DDS::OctetSeq& future_challenge = initiator_remote_auth_request.get_bin_property_value("future_challenge");
666 :
667 6 : if (! challenges_match(challenge1, future_challenge)) {
668 0 : return Failure;
669 : }
670 : }
671 :
672 7 : const LocalAuthCredentialData& local_credential_data = *(local_data.credentials);
673 :
674 7 : const DDS::OctetSeq& cid = message_in.get_bin_property_value("c.id");
675 7 : if (cid.length() > 0) {
676 :
677 7 : remote_cert->deserialize(cid);
678 7 : if (X509_V_OK != remote_cert->validate(local_credential_data.get_ca_cert()))
679 : {
680 0 : set_security_error(ex, -1, 0, "Certificate validation failed");
681 0 : return Failure;
682 : }
683 :
684 : } else {
685 0 : set_security_error(ex, -1, 0, "Certificate validation failed due to empty 'c.id' property supplied");
686 0 : return Failure;
687 : }
688 :
689 : /* Validate participant_guid in c.pdata */
690 :
691 7 : const DDS::OctetSeq& cpdata = message_in.get_bin_property_value("c.pdata");
692 :
693 7 : std::vector<unsigned char> hash;
694 7 : if (0 != remote_cert->subject_name_digest(hash)) {
695 0 : set_security_error(ex, -1, 0, "Failed to generate subject-name digest from remote certificate.");
696 0 : return Failure;
697 : }
698 :
699 7 : if (! validate_topic_data_guid(cpdata, hash, ex)) {
700 0 : return Failure;
701 : }
702 :
703 7 : cperm = message_in.get_bin_property_value("c.perm");
704 :
705 7 : const DDS::OctetSeq& dh_algo = message_in.get_bin_property_value("c.kagree_algo");
706 7 : diffie_hellman.reset(SSL::DiffieHellman::factory(dh_algo));
707 :
708 : /* Compute hash_c1 and store for later */
709 :
710 : {
711 7 : CredentialHash hash(*remote_cert,
712 7 : *diffie_hellman,
713 : cpdata,
714 7 : cperm);
715 7 : int err = hash(hash_c1);
716 7 : if (err) {
717 0 : set_security_error(ex, -1, 0, "Failed to compute hash_c1.");
718 0 : return Failure;
719 : }
720 : }
721 :
722 : /* Compute hash_c2 and store for later */
723 :
724 : {
725 : CredentialHash hash(local_credential_data.get_participant_cert(),
726 7 : *diffie_hellman,
727 : serialized_local_participant_data,
728 14 : local_credential_data.get_access_permissions());
729 7 : int err = hash(hash_c2);
730 7 : if (err) {
731 0 : set_security_error(ex, -1, 0, "Failed to compute hash_c2.");
732 0 : return Failure;
733 : }
734 : }
735 :
736 : // TODO: Currently support for OCSP is optional in the security spec and
737 : // so it has been deferred to a post-beta release.
738 : // Add OCSP checks when "ocsp_status" property is given in message_in.
739 : // Most of this logic would probably be placed in the Certificate directly
740 : // or an OCSP abstraction that the Certificate uses.
741 :
742 7 : const DDS::OctetSeq& dh1 = message_in.get_bin_property_value("dh1");
743 :
744 7 : TokenWriter message_out(handshake_message_out, build_class_id(Handshake_Reply_Class_Ext));
745 :
746 7 : message_out.add_bin_property("c.id", local_credential_data.get_participant_cert().original_bytes());
747 7 : message_out.add_bin_property("c.perm", local_credential_data.get_access_permissions());
748 7 : message_out.add_bin_property("c.pdata", serialized_local_participant_data);
749 7 : message_out.add_bin_property("c.dsign_algo", local_credential_data.get_participant_cert().dsign_algo());
750 7 : message_out.add_bin_property("c.kagree_algo", diffie_hellman->kagree_algo());
751 :
752 7 : if (local_data.handshake_debug) {
753 0 : message_out.add_bin_property("hash_c2", hash_c2);
754 : }
755 :
756 7 : diffie_hellman->pub_key(dh2);
757 7 : message_out.add_bin_property("dh2", dh2);
758 :
759 7 : if (local_data.handshake_debug) {
760 0 : message_out.add_bin_property("hash_c1", hash_c1);
761 0 : message_out.add_bin_property("dh1", dh1);
762 : }
763 :
764 7 : message_out.add_bin_property("challenge1", challenge1);
765 :
766 7 : TokenReader initiator_local_auth_request(remote_data.local_auth_request);
767 7 : if (! initiator_local_auth_request.is_nil()) {
768 7 : const DDS::OctetSeq& future_challenge = initiator_local_auth_request.get_bin_property_value("future_challenge");
769 7 : message_out.add_bin_property("challenge2", future_challenge);
770 7 : challenge2 = future_challenge;
771 :
772 : } else {
773 0 : int err = SSL::make_nonce_256(challenge2);
774 0 : if (! err) {
775 0 : message_out.add_bin_property("challenge2", challenge2);
776 :
777 : } else {
778 0 : set_security_error(ex, -1, 0, "SSL::make_nonce_256 failed.");
779 0 : return Failure;
780 : }
781 : }
782 :
783 7 : DDS::BinaryPropertySeq sign_these;
784 7 : make_reply_signature_sequence(hash_c2,
785 : challenge2,
786 : dh2,
787 : challenge1,
788 : dh1,
789 : hash_c1,
790 : sign_these);
791 :
792 7 : DDS::OctetSeq signature;
793 7 : SSL::sign_serialized(sign_these, local_credential_data.get_participant_private_key(), signature);
794 7 : message_out.add_bin_property("signature", signature);
795 :
796 7 : remote_data.replier_identity = replier_identity_handle;
797 7 : remote_data.initiator_identity = initiator_identity_handle;
798 7 : remote_data.state = DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE;
799 7 : remote_data.diffie_hellman = DCPS::move(diffie_hellman);
800 7 : remote_data.certificate = DCPS::move(remote_cert);
801 7 : remote_data.c_perm = cperm;
802 7 : remote_data.reply = handshake_message_out;
803 7 : remote_data.request = request_token;
804 7 : remote_data.hash_c1 = hash_c1;
805 7 : remote_data.hash_c2 = hash_c2;
806 :
807 7 : if (handshake_handle == DDS::HANDLE_NIL) {
808 6 : handshake_handle = get_next_handle();
809 : }
810 :
811 : {
812 7 : ACE_Guard<ACE_Thread_Mutex> guard(handshake_mutex_);
813 7 : handshake_data_[handshake_handle] = handshake_data;
814 :
815 7 : if (DCPS::security_debug.bookkeeping) {
816 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
817 : ACE_TEXT("AuthenticationBuiltInImpl::begin_handshake_reply handshake_data_ (total %B)\n"),
818 : handshake_data_.size()));
819 : }
820 7 : }
821 :
822 7 : return Pending;
823 7 : }
824 :
825 10 : ::DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_handshake(
826 : ::DDS::Security::HandshakeMessageToken & handshake_message_out,
827 : const ::DDS::Security::HandshakeMessageToken & handshake_message_in,
828 : ::DDS::Security::HandshakeHandle handshake_handle,
829 : ::DDS::Security::SecurityException & ex)
830 : {
831 10 : const std::string incoming_class_ext = get_extension(handshake_message_in.class_id);
832 :
833 10 : if (Handshake_Reply_Class_Ext == incoming_class_ext) {
834 5 : return process_handshake_reply(handshake_message_out, handshake_message_in, handshake_handle, ex);
835 :
836 5 : } else if (Handshake_Final_Class_Ext == incoming_class_ext) {
837 5 : return process_final_handshake(handshake_message_in, handshake_handle, ex);
838 : }
839 :
840 0 : return DDS::Security::VALIDATION_PENDING_RETRY;
841 10 : }
842 :
843 2 : ::DDS::Security::SharedSecretHandle* AuthenticationBuiltInImpl::get_shared_secret(
844 : ::DDS::Security::HandshakeHandle handshake_handle,
845 : ::DDS::Security::SecurityException & ex)
846 : {
847 : using namespace DDS::Security;
848 :
849 2 : SharedSecretHandle* result = 0;
850 :
851 2 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
852 :
853 2 : HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
854 2 : if (handshake_data.first && handshake_data.second) {
855 :
856 2 : ValidationResult_t state = handshake_data.second->state;
857 2 : if (state == VALIDATION_OK || state == VALIDATION_OK_FINAL_MESSAGE) {
858 2 : SharedSecretHandle_var handle = handshake_data.second->shared_secret;
859 2 : result = handle._retn();
860 :
861 2 : } else {
862 0 : set_security_error(ex, -1, 0, "Validation state must be either VALIDATION_OK or VALIDATION_OK_FINAL_MESSAGE");
863 : }
864 :
865 : } else {
866 0 : set_security_error(ex, -1, 0, "Unknown handshake handle");
867 : }
868 :
869 2 : return result;
870 2 : }
871 :
872 2 : ::CORBA::Boolean AuthenticationBuiltInImpl::get_authenticated_peer_credential_token(
873 : ::DDS::Security::AuthenticatedPeerCredentialToken & peer_credential_token,
874 : ::DDS::Security::HandshakeHandle handshake_handle,
875 : ::DDS::Security::SecurityException & ex)
876 : {
877 : using namespace DDS::Security;
878 2 : ::CORBA::Boolean result = false;
879 :
880 2 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
881 :
882 2 : HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
883 2 : if (handshake_data.first && handshake_data.second) {
884 2 : ValidationResult_t state = handshake_data.second->state;
885 2 : if (state == VALIDATION_OK || state == VALIDATION_OK_FINAL_MESSAGE) {
886 4 : OpenDDS::Security::TokenWriter peer_token(peer_credential_token, Auth_Peer_Cred_Token_Class_Id);
887 :
888 2 : DDS::BinaryPropertySeq& props = peer_credential_token.binary_properties;
889 2 : props.length(2);
890 :
891 2 : DDS::BinaryProperty_t p1;
892 2 : p1.name = "c.id";
893 2 : p1.value = handshake_data.second->certificate->original_bytes();
894 2 : p1.propagate = true;
895 :
896 2 : DDS::BinaryProperty_t p2;
897 2 : p2.name = "c.perm";
898 2 : p2.value = handshake_data.second->c_perm;
899 2 : p2.propagate = true;
900 :
901 2 : props[0] = p1;
902 2 : props[1] = p2;
903 :
904 2 : result = true;
905 :
906 2 : } else {
907 0 : set_security_error(ex, -1, 0, "Validation state must be either VALIDATION_OK or VALIDATION_OK_FINAL_MESSAGE");
908 : }
909 :
910 : } else {
911 0 : set_security_error(ex, -1, 0, "Unknown handshake handle");
912 : }
913 :
914 2 : return result;
915 2 : }
916 :
917 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::set_listener(
918 : ::DDS::Security::AuthenticationListener_ptr listener,
919 : ::DDS::Security::SecurityException & ex)
920 : {
921 0 : ::CORBA::Boolean results = false;
922 :
923 0 : if (!listener) {
924 0 : set_security_error(ex, -1, 0, "Null listener provided");
925 : } else {
926 0 : results = true;
927 0 : listener_ptr_ = listener;
928 : }
929 0 : return results;
930 : }
931 :
932 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_token(
933 : const ::DDS::Security::IdentityToken & token,
934 : ::DDS::Security::SecurityException & ex)
935 : {
936 : // Nothing to do here yet
937 : ACE_UNUSED_ARG(token);
938 : ACE_UNUSED_ARG(ex);
939 0 : return true;
940 : }
941 :
942 :
943 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_status_token(
944 : const ::DDS::Security::IdentityStatusToken & token,
945 : ::DDS::Security::SecurityException & ex)
946 : {
947 : // Nothing to do here yet
948 : ACE_UNUSED_ARG(token);
949 : ACE_UNUSED_ARG(ex);
950 0 : return true;
951 : }
952 :
953 :
954 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_authenticated_peer_credential_token(
955 : const ::DDS::Security::AuthenticatedPeerCredentialToken & peer_credential_token,
956 : ::DDS::Security::SecurityException & ex)
957 : {
958 : // Nothing to do here yet
959 : ACE_UNUSED_ARG(peer_credential_token);
960 : ACE_UNUSED_ARG(ex);
961 0 : return true;
962 : }
963 :
964 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_handshake_handle(
965 : ::DDS::Security::HandshakeHandle handshake_handle,
966 : ::DDS::Security::SecurityException & ex)
967 : {
968 0 : ACE_Guard<ACE_Thread_Mutex> guard(handshake_mutex_);
969 :
970 0 : HandshakeDataMap::iterator found = handshake_data_.find(handshake_handle);
971 0 : if (found != handshake_data_.end()) {
972 0 : handshake_data_.erase(found);
973 :
974 0 : if (DCPS::security_debug.bookkeeping) {
975 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
976 : ACE_TEXT("AuthenticationBuiltInImpl::return_handshake_handle handshake_data_ (total %B)\n"),
977 : handshake_data_.size()));
978 : }
979 :
980 0 : return true;
981 : }
982 :
983 0 : set_security_error(ex, -1, 0, "Handshake handle not recognized");
984 0 : return false;
985 0 : }
986 :
987 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_identity_handle(
988 : ::DDS::Security::IdentityHandle identity_handle,
989 : ::DDS::Security::SecurityException & ex)
990 : {
991 0 : ACE_Guard<ACE_Thread_Mutex> guard(identity_mutex_);
992 :
993 0 : LocalParticipantMap::iterator local = local_participants_.find(identity_handle);
994 :
995 0 : if (local != local_participants_.end()) {
996 :
997 : {
998 0 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
999 :
1000 0 : for (HandshakeDataMap::iterator it = handshake_data_.begin(); it != handshake_data_.end(); /* increment in loop*/) {
1001 0 : if (it->second.first == local->second) {
1002 0 : handshake_data_.erase(it++);
1003 : } else {
1004 0 : ++it;
1005 : }
1006 : }
1007 0 : }
1008 :
1009 0 : local_participants_.erase(local);
1010 :
1011 0 : if (DCPS::security_debug.bookkeeping) {
1012 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
1013 : ACE_TEXT("AuthenticationBuiltInImpl::return_identity_handle local_participants_ (total %B)\n"),
1014 : local_participants_.size()));
1015 : }
1016 :
1017 0 : return true;
1018 : }
1019 :
1020 0 : local = std::find_if(local_participants_.begin(), local_participants_.end(),
1021 : local_has_remote_handle(identity_handle));
1022 :
1023 0 : if (local != local_participants_.end()) {
1024 :
1025 0 : const RemoteParticipantMap::iterator remote = local->second->validated_remotes.find(identity_handle);
1026 :
1027 : {
1028 0 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
1029 :
1030 0 : for (HandshakeDataMap::iterator it = handshake_data_.begin(); it != handshake_data_.end(); /* increment in loop*/) {
1031 0 : if (it->second.second == remote->second) {
1032 0 : handshake_data_.erase(it++);
1033 : } else {
1034 0 : ++it;
1035 : }
1036 : }
1037 0 : }
1038 :
1039 0 : local->second->validated_remotes.erase(remote);
1040 :
1041 0 : if (DCPS::security_debug.bookkeeping) {
1042 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
1043 : ACE_TEXT("AuthenticationBuiltInImpl::return_identity_handle validated_remotes (total %B)\n"),
1044 : local->second->validated_remotes.size()));
1045 : }
1046 :
1047 0 : return true;
1048 : }
1049 :
1050 0 : set_security_error(ex, -1, 0, "Identity handle not recognized");
1051 0 : return false;
1052 0 : }
1053 :
1054 0 : ::CORBA::Boolean AuthenticationBuiltInImpl::return_sharedsecret_handle(
1055 : ::DDS::Security::SharedSecretHandle* sharedsecret_handle,
1056 : ::DDS::Security::SecurityException & ex)
1057 : {
1058 : // Nothing to do here in the stub version
1059 : ACE_UNUSED_ARG(sharedsecret_handle);
1060 : ACE_UNUSED_ARG(ex);
1061 0 : return true;
1062 : }
1063 :
1064 :
1065 5 : DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_handshake_reply(
1066 : DDS::Security::HandshakeMessageToken & handshake_message_out,
1067 : const DDS::Security::HandshakeMessageToken & handshake_message_in,
1068 : DDS::Security::HandshakeHandle handshake_handle,
1069 : DDS::Security::SecurityException & ex)
1070 : {
1071 5 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
1072 5 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
1073 :
1074 5 : DDS::OctetSeq challenge1, hash_c2;
1075 5 : SSL::Certificate::unique_ptr remote_cert(new SSL::Certificate);
1076 :
1077 5 : const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED;
1078 5 : const DDS::Security::ValidationResult_t FinalMessage = DDS::Security::VALIDATION_OK_FINAL_MESSAGE;
1079 :
1080 5 : HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
1081 5 : if (!handshake_data.first || !handshake_data.second) {
1082 0 : set_security_error(ex, -1, 0, "Unknown handshake handle");
1083 0 : return Failure;
1084 : }
1085 :
1086 5 : LocalParticipantData& local_data = *(handshake_data.first);
1087 5 : RemoteParticipantData& remote_data = *(handshake_data.second);
1088 :
1089 5 : if (remote_data.state != DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE) {
1090 0 : set_security_error(ex, -1, 0, "Handshake state is not valid");
1091 0 : return Failure;
1092 : }
1093 :
1094 5 : TokenReader message_in(handshake_message_in);
1095 5 : if (message_in.is_nil()) {
1096 0 : set_security_error(ex, -1, 0, "Handshake_message_in must not be nil");
1097 0 : return Failure;
1098 : }
1099 :
1100 5 : const DDS::OctetSeq& challenge2 = message_in.get_bin_property_value("challenge2");
1101 :
1102 5 : TokenReader auth_wrapper(remote_data.remote_auth_request);
1103 5 : if (! auth_wrapper.is_nil()) {
1104 0 : const DDS::OctetSeq& future_challenge = auth_wrapper.get_bin_property_value("future_challenge");
1105 :
1106 0 : if (! challenges_match(challenge2, future_challenge)) {
1107 0 : set_security_error(ex, -1, 0, "challenge2 does not match future_challenge");
1108 0 : return Failure;
1109 : }
1110 : }
1111 :
1112 5 : const LocalAuthCredentialData& local_credential_data = *(local_data.credentials);
1113 :
1114 5 : const DDS::OctetSeq& cid = message_in.get_bin_property_value("c.id");
1115 5 : if (cid.length() > 0) {
1116 :
1117 5 : remote_cert->deserialize(cid);
1118 :
1119 5 : if (X509_V_OK != remote_cert->validate(local_credential_data.get_ca_cert()))
1120 : {
1121 0 : set_security_error(ex, -1, 0, "Certificate validation failed");
1122 0 : return Failure;
1123 : }
1124 :
1125 : } else {
1126 0 : set_security_error(ex, -1, 0, "Certificate validation failed due to empty 'c.id' property supplied");
1127 0 : return Failure;
1128 : }
1129 :
1130 : /* Check that challenge1 on message_in matches the one sent in HandshakeRequestMessageToken */
1131 :
1132 5 : TokenReader handshake_request_token(remote_data.request);
1133 5 : if (handshake_request_token.is_nil()) {
1134 0 : set_security_error(ex, -1, 0, "Handshake-request-token is nil");
1135 0 : return Failure;
1136 :
1137 : } else {
1138 5 : challenge1 = handshake_request_token.get_bin_property_value("challenge1");
1139 5 : const DDS::OctetSeq& challenge1_reply = message_in.get_bin_property_value("challenge1");
1140 :
1141 5 : if (! challenges_match(challenge1, challenge1_reply)) {
1142 0 : set_security_error(ex, -1, 0, "handshake-request challenge1 value does not match local challenge1");
1143 0 : return Failure;
1144 : }
1145 : }
1146 :
1147 : /* Validate participant_guid in c.pdata */
1148 :
1149 5 : const DDS::OctetSeq& cpdata = message_in.get_bin_property_value("c.pdata");
1150 :
1151 5 : std::vector<unsigned char> hash;
1152 5 : if (0 != remote_cert->subject_name_digest(hash)) {
1153 0 : set_security_error(ex, -1, 0, "Failed to generate subject-name digest from remote certificate.");
1154 0 : return Failure;
1155 : }
1156 :
1157 5 : if (! validate_topic_data_guid(cpdata, hash, ex)) {
1158 0 : return Failure;
1159 : }
1160 :
1161 : /* Compute/Store the Diffie-Hellman shared-secret */
1162 :
1163 5 : const DDS::OctetSeq& dh2 = message_in.get_bin_property_value("dh2");
1164 5 : if (0 != remote_data.diffie_hellman->gen_shared_secret(dh2)) {
1165 0 : set_security_error(ex, -1, 0, "Failed to generate shared secret from dh1 and dh2");
1166 0 : return Failure;
1167 : }
1168 :
1169 5 : const DDS::OctetSeq& cperm = message_in.get_bin_property_value("c.perm");
1170 :
1171 : /* Compute hash_c2 and store for later (hash_c1 was already computed in request) */
1172 :
1173 : {
1174 5 : CredentialHash hash(*remote_cert,
1175 5 : *remote_data.diffie_hellman,
1176 : cpdata,
1177 5 : cperm);
1178 5 : int err = hash(hash_c2);
1179 5 : if (err) {
1180 0 : set_security_error(ex, -1, 0, "Computing hash_c2 failed");
1181 0 : return Failure;
1182 : }
1183 : }
1184 :
1185 : /* Validate Signature field */
1186 5 : const DDS::OctetSeq& dh1 = handshake_request_token.get_bin_property_value("dh1");
1187 :
1188 5 : DDS::BinaryPropertySeq verify_these;
1189 5 : make_reply_signature_sequence(hash_c2,
1190 : challenge2,
1191 : dh2,
1192 : challenge1,
1193 : dh1,
1194 5 : remote_data.hash_c1,
1195 : verify_these);
1196 :
1197 5 : const DDS::OctetSeq& remote_signature = message_in.get_bin_property_value("signature");
1198 :
1199 5 : int err = SSL::verify_serialized(verify_these, *remote_cert, remote_signature);
1200 5 : if (err) {
1201 0 : set_security_error(ex, -1, 0, "Remote 'signature' field failed signature verification");
1202 0 : return Failure;
1203 : }
1204 :
1205 5 : OpenDDS::Security::TokenWriter final_msg(handshake_message_out, build_class_id(Handshake_Final_Class_Ext));
1206 :
1207 5 : if (local_data.handshake_debug) {
1208 0 : final_msg.add_bin_property("hash_c1", remote_data.hash_c1);
1209 0 : final_msg.add_bin_property("hash_c2", hash_c2);
1210 0 : final_msg.add_bin_property("dh1", dh1);
1211 0 : final_msg.add_bin_property("dh2", dh2);
1212 : }
1213 :
1214 5 : final_msg.add_bin_property("challenge1", challenge1);
1215 5 : final_msg.add_bin_property("challenge2", challenge2);
1216 :
1217 5 : DDS::BinaryPropertySeq sign_these;
1218 5 : make_final_signature_sequence(remote_data.hash_c1,
1219 : challenge1,
1220 : dh1,
1221 : challenge2,
1222 : dh2,
1223 : hash_c2,
1224 : sign_these);
1225 :
1226 5 : DDS::OctetSeq tmp;
1227 5 : SSL::sign_serialized(sign_these, local_credential_data.get_participant_private_key(), tmp);
1228 5 : final_msg.add_bin_property("signature", tmp);
1229 :
1230 5 : remote_data.certificate = DCPS::move(remote_cert);
1231 5 : remote_data.state = FinalMessage;
1232 5 : remote_data.c_perm = message_in.get_bin_property_value("c.perm");
1233 5 : remote_data.hash_c2 = hash_c2;
1234 10 : remote_data.shared_secret = new SharedSecret(challenge1,
1235 : challenge2,
1236 5 : remote_data.diffie_hellman->get_shared_secret());
1237 5 : return FinalMessage;
1238 5 : }
1239 :
1240 21 : bool challenges_match(const DDS::OctetSeq& c1, const DDS::OctetSeq& c2)
1241 : {
1242 21 : if ((c1.length()) < 1 || (c2.length() < 1)) {
1243 0 : return false;
1244 : }
1245 21 : if (c1.length() != c2.length()) {
1246 0 : return false;
1247 : }
1248 :
1249 21 : if (0 != std::memcmp(c1.get_buffer(), c2.get_buffer(), c2.length())) {
1250 0 : return false;
1251 : }
1252 :
1253 21 : return true;
1254 : }
1255 :
1256 5 : DDS::Security::ValidationResult_t AuthenticationBuiltInImpl::process_final_handshake(
1257 : const DDS::Security::HandshakeMessageToken & handshake_message_in, /* Final message token */
1258 : DDS::Security::HandshakeHandle handshake_handle,
1259 : DDS::Security::SecurityException & ex)
1260 : {
1261 5 : const DDS::Security::ValidationResult_t Failure = DDS::Security::VALIDATION_FAILED;
1262 5 : const DDS::Security::ValidationResult_t ValidationOkay = DDS::Security::VALIDATION_OK;
1263 :
1264 5 : ACE_Guard<ACE_Thread_Mutex> identity_data_guard(identity_mutex_);
1265 5 : ACE_Guard<ACE_Thread_Mutex> handshake_data_guard(handshake_mutex_);
1266 :
1267 5 : HandshakeDataPair handshake_data = get_handshake_data(handshake_handle);
1268 5 : if (!handshake_data.first || !handshake_data.second) {
1269 0 : set_security_error(ex, -1, 0, "Unknown handshake handle");
1270 0 : return Failure;
1271 : }
1272 :
1273 5 : RemoteParticipantData& remote_data = *(handshake_data.second);
1274 :
1275 5 : if (remote_data.state != DDS::Security::VALIDATION_PENDING_HANDSHAKE_MESSAGE) {
1276 0 : set_security_error(ex, -1, 0, "Handshake state is not valid");
1277 0 : return Failure;
1278 : }
1279 :
1280 : /* Check challenge1 and challenge2 match what was sent with the reply-message-token */
1281 :
1282 5 : TokenReader handshake_final_token(handshake_message_in);
1283 5 : if (handshake_final_token.is_nil()) {
1284 0 : set_security_error(ex, -1, 0, "Handshake-final-token is nil");
1285 0 : return Failure;
1286 : }
1287 :
1288 5 : TokenReader handshake_reply_token(remote_data.reply);
1289 5 : if (handshake_reply_token.is_nil()) {
1290 0 : set_security_error(ex, -1, 0, "Handshake-reply-token is nil");
1291 0 : return Failure;
1292 : }
1293 :
1294 : /* Per the spec, dh1 is optional in all _but_ the request token so it's grabbed from the request */
1295 5 : TokenReader handshake_request_token(remote_data.request);
1296 5 : if (handshake_reply_token.is_nil()) {
1297 0 : set_security_error(ex, -1, 0, "Handshake-reply-token is nil");
1298 0 : return Failure;
1299 : }
1300 :
1301 5 : const DDS::OctetSeq& dh1 = handshake_request_token.get_bin_property_value("dh1");
1302 5 : const DDS::OctetSeq& dh2 = handshake_reply_token.get_bin_property_value("dh2");
1303 :
1304 5 : const DDS::OctetSeq& challenge1_reply = handshake_reply_token.get_bin_property_value("challenge1");
1305 5 : const DDS::OctetSeq& challenge2_reply = handshake_reply_token.get_bin_property_value("challenge2");
1306 :
1307 5 : const DDS::OctetSeq& challenge1_final = handshake_final_token.get_bin_property_value("challenge1");
1308 5 : const DDS::OctetSeq& challenge2_final = handshake_final_token.get_bin_property_value("challenge2");
1309 :
1310 5 : if (! challenges_match(challenge1_reply, challenge1_final) || ! challenges_match(challenge2_reply, challenge2_final)) {
1311 0 : return Failure;
1312 : }
1313 :
1314 : /* Validate Signature field */
1315 :
1316 5 : const SSL::Certificate::unique_ptr& remote_cert = remote_data.certificate;
1317 :
1318 5 : DDS::BinaryPropertySeq verify_these;
1319 5 : make_final_signature_sequence(remote_data.hash_c1,
1320 : challenge1_reply,
1321 : dh1,
1322 : challenge2_reply,
1323 : dh2,
1324 5 : remote_data.hash_c2,
1325 : verify_these);
1326 :
1327 5 : const DDS::OctetSeq& remote_signature = handshake_final_token.get_bin_property_value("signature");
1328 :
1329 5 : int err = SSL::verify_serialized(verify_these, *remote_cert, remote_signature);
1330 5 : if (err) {
1331 0 : set_security_error(ex, -1, 0, "Remote 'signature' field failed signature verification");
1332 0 : return Failure;
1333 : }
1334 :
1335 : /* Compute/Store the Diffie-Hellman shared-secret */
1336 :
1337 5 : if (0 != remote_data.diffie_hellman->gen_shared_secret(dh1)) {
1338 0 : set_security_error(ex, -1, 0, "Failed to generate shared secret from dh2 and dh1");
1339 0 : return Failure;
1340 : }
1341 :
1342 5 : remote_data.state = DDS::Security::VALIDATION_OK;
1343 10 : remote_data.shared_secret = new SharedSecret(challenge1_reply,
1344 : challenge2_reply,
1345 5 : remote_data.diffie_hellman->get_shared_secret());
1346 :
1347 5 : return ValidationOkay;
1348 5 : }
1349 :
1350 : AuthenticationBuiltInImpl::LocalParticipantData::shared_ptr
1351 37 : AuthenticationBuiltInImpl::get_local_participant(DDS::Security::IdentityHandle handle)
1352 : {
1353 37 : LocalParticipantMap::iterator found = local_participants_.find(handle);
1354 37 : if (found != local_participants_.end()) {
1355 37 : return found->second;
1356 : }
1357 :
1358 0 : return LocalParticipantData::shared_ptr();
1359 : }
1360 :
1361 44 : AuthenticationBuiltInImpl::LocalParticipantData::~LocalParticipantData()
1362 : {
1363 22 : if (DCPS::security_debug.bookkeeping) {
1364 0 : ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) {bookkeeping} ")
1365 : ACE_TEXT("LocalParticipantData::~LocalParticipantData validated_remotes %B\n"),
1366 : validated_remotes.size()));
1367 : }
1368 44 : }
1369 :
1370 : AuthenticationBuiltInImpl::HandshakeDataPair
1371 14 : AuthenticationBuiltInImpl::get_handshake_data(DDS::Security::HandshakeHandle handle)
1372 : {
1373 14 : HandshakeDataMap::iterator found = handshake_data_.find(handle);
1374 14 : if (found != handshake_data_.end()) {
1375 14 : return found->second;
1376 : }
1377 :
1378 0 : return HandshakeDataPair();
1379 : }
1380 :
1381 : AuthenticationBuiltInImpl::HandshakeDataPair
1382 14 : AuthenticationBuiltInImpl::make_handshake_pair(DDS::Security::IdentityHandle h1,
1383 : DDS::Security::IdentityHandle h2)
1384 : {
1385 14 : DDS::Security::IdentityHandle other = DDS::HANDLE_NIL;
1386 :
1387 14 : LocalParticipantMap::iterator found_local = local_participants_.find(h1);
1388 14 : if (found_local != local_participants_.end()) {
1389 7 : other = h2;
1390 :
1391 : } else {
1392 7 : found_local = local_participants_.find(h2);
1393 7 : if (found_local != local_participants_.end()) {
1394 7 : other = h1;
1395 :
1396 : } else {
1397 0 : return HandshakeDataPair();
1398 : }
1399 : }
1400 :
1401 14 : RemoteParticipantMap::iterator found_remote = found_local->second->validated_remotes.find(other);
1402 14 : if (found_remote != found_local->second->validated_remotes.end()) {
1403 14 : return std::make_pair(found_local->second, found_remote->second);
1404 : }
1405 :
1406 0 : return HandshakeDataPair();
1407 : }
1408 :
1409 16 : bool AuthenticationBuiltInImpl::is_handshake_initiator(
1410 : const OpenDDS::DCPS::GUID_t& local, const OpenDDS::DCPS::GUID_t& remote)
1411 : {
1412 16 : const unsigned char* local_ = reinterpret_cast<const unsigned char*>(&local);
1413 16 : const unsigned char* remote_ = reinterpret_cast<const unsigned char*>(&remote);
1414 :
1415 : using DCPS::SecurityDebug;
1416 16 : if (DCPS::security_debug.force_auth_role != SecurityDebug::FORCE_AUTH_ROLE_NORMAL) {
1417 0 : return DCPS::security_debug.force_auth_role == SecurityDebug::FORCE_AUTH_ROLE_LEADER;
1418 : }
1419 :
1420 : /* if remote > local, pending request; else pending handshake message */
1421 16 : return std::lexicographical_compare(local_, local_ + sizeof(local),
1422 16 : remote_, remote_ + sizeof(remote));
1423 :
1424 : }
1425 :
1426 16 : bool AuthenticationBuiltInImpl::check_class_versions(const char* remote_class_id)
1427 : {
1428 16 : if (!remote_class_id) {
1429 0 : return false;
1430 : }
1431 16 : bool class_matches = false;
1432 :
1433 : // Slow, but this is just for the stub
1434 16 : std::string class_id_str(remote_class_id);
1435 :
1436 : // Class name is the text prior to the final ':'
1437 16 : size_t colon_pos = class_id_str.find_last_of(':');
1438 16 : if (std::string::npos != colon_pos && colon_pos > 0) {
1439 : // Compare the class name vs the expected class name
1440 16 : std::string remote_class_name = class_id_str.substr(0, colon_pos);
1441 16 : if (0 == Auth_Plugin_Name.compare(remote_class_name)) {
1442 : // Major version is the text between the final : and a .
1443 16 : size_t major_start = colon_pos + 1;
1444 16 : size_t period_pos = class_id_str.find_first_of('.', major_start);
1445 16 : if (std::string::npos != period_pos && period_pos > major_start) {
1446 16 : std::string major_version = class_id_str.substr(major_start, period_pos - major_start);
1447 16 : if (0 == Auth_Plugin_Major_Version.compare(major_version)) {
1448 16 : class_matches = true;
1449 : }
1450 16 : }
1451 : }
1452 16 : }
1453 :
1454 16 : return class_matches;
1455 16 : }
1456 :
1457 35 : std::string AuthenticationBuiltInImpl::build_class_id(const std::string& message_ext)
1458 : {
1459 35 : std::string class_id_stream = Auth_Plugin_Name +
1460 70 : + ":" + Auth_Plugin_Major_Version
1461 70 : + "." + Auth_Plugin_Minor_Version
1462 70 : + "+" + message_ext;
1463 :
1464 35 : return class_id_stream;
1465 : }
1466 :
1467 10 : std::string AuthenticationBuiltInImpl::get_extension(const char* class_id)
1468 : {
1469 10 : std::string ext_string("");
1470 :
1471 10 : std::string class_id_str(class_id);
1472 10 : size_t extension_delim_pos = class_id_str.find_last_of('+');
1473 10 : if (extension_delim_pos != std::string::npos) {
1474 10 : size_t start_ext_pos = extension_delim_pos + 1;
1475 10 : if (start_ext_pos < class_id_str.length()) {
1476 10 : ext_string = class_id_str.substr(start_ext_pos);
1477 : }
1478 : }
1479 :
1480 20 : return ext_string;
1481 10 : }
1482 :
1483 51 : CORBA::Long AuthenticationBuiltInImpl::get_next_handle()
1484 : {
1485 51 : ACE_Guard<ACE_Thread_Mutex> guard(handle_mutex_);
1486 102 : return CommonUtilities::increment_handle(next_handle_);
1487 51 : }
1488 :
1489 : } // namespace Security
1490 : } // namespace OpenDDS
1491 :
1492 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
|