1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <errno.h>
28
29 #if !defined(UNIX) && !defined(METAWARE)
30 #include "KMSAgent_direct.h"
31 #endif
32
33 #include <string.h>
34
35 #include "KMSClientProfile.h"
36
37 #include "KMSAgent.h"
38 #include "KMS_CAStub.h"
39 #include "KMS_CertificateStub.h"
40 #include "KMS_DiscoveryStub.h"
41 #include "KMSClientProfileImpl.h"
42 #include "KMSAuditLogger.h"
43 #include "KMSAgentSoapUtilities.h"
44 #include "KMSAgentStringUtilities.h"
45
46
47 #include "KMSAgentPKICommon.h" // must be before agentstorage
48
49 #include "stdsoap2.h"
50 #include "KMSAgentStorage.h" // uses KMSClientProfile
51
52
53 #include "KMSAgentWebServiceNamespaces.h"
54 #include "k_setupssl.h"
55 #include "KMSAgentChallenge.h"
56 #include "KMSAgentCryptoUtilities.h"
57 #include "ApplianceParameters.h"
58 #include "AutoMutex.h"
59
60 #include "KMSAgentLoadBalancer.h"
61 #include "KMSAgentDataUnitCache.h"
62
63 #include "ClientSoapFaultCodes.h"
64 #ifdef METAWARE
65 #include "debug.h"
66 #include "sizet.h"
67 typedef unsigned char uint8_t;
68 typedef unsigned short uint16_t;
69 typedef unsigned int uint32_t;
70 typedef unsigned long long uint64_t;
71 #include "literals.h"
72 #endif
73 #include "KMSAgentAESKeyWrap.h"
74
75 #if defined(METAWARE) && defined(DEBUG)
76 #include "debug.h"
77 #endif
78 #include "KMSAuditLogger.h"
79 #include "KMSClientProfileImpl.h"
80
81 #ifdef METAWARE
82 extern "C" void
83 tnMsg( const char *format,
84 ... );
85 #endif
86
87 bool g_bUseFileLog = false;
88 char g_wsWorkingDirectory[KMS_MAX_PATH_LENGTH+1] = "./";
89
90
InitializeLogging(const utf8cstr i_wsWorkingDirectory,int i_bUseFileLog)91 static bool InitializeLogging(
92 const utf8cstr i_wsWorkingDirectory,
93 int i_bUseFileLog )
94 {
95 FATAL_ASSERT( !i_bUseFileLog || i_wsWorkingDirectory );
96
97 bool bFileLogSuccess = true;
98
99 g_bUseFileLog = ( i_bUseFileLog != 0 );
100
101 // InitializeFileLogging must always be called,
102 // because the file is always used by FATALs.
103
104 bFileLogSuccess = InitializeFileLogging( i_wsWorkingDirectory ) ? true:false;
105
106 return bFileLogSuccess;
107 }
108
FinalizeLogging()109 static void FinalizeLogging()
110 {
111 // FinalizeFileLogging must always be called,
112 // because the file is always used by FATALs.
113 FinalizeFileLogging();
114
115 return;
116 }
117
118
119
120
121 /*---------------------------------------------------------------------------
122 * Function: KMSClient_InitializeLibrary
123 *
124 *--------------------------------------------------------------------------*/
125
KMSClient_InitializeLibrary(const utf8cstr i_wsWorkingDirectory,int i_bUseFileLog)126 bool KMSClient_InitializeLibrary(
127 const utf8cstr i_wsWorkingDirectory,
128 int i_bUseFileLog)
129 {
130 bool bSuccess;
131
132 #if defined(DEBUG) && defined(METAWARE)
133 log_printf("KMSClient_InitializeLibrary : ENTERING");
134 #endif
135
136 // setup SSL
137 bSuccess = K_SetupSSL() == 1;
138 if(!bSuccess)
139 {
140 return false;
141 }
142
143 #if defined(DEBUG) && defined(METAWARE)
144 log_printf("KMSClient_InitializeLibrary : set current directory");
145 #endif
146
147 // if i_wsWorkingDirectory is null, caller means current directory
148 if ( i_wsWorkingDirectory != NULL )
149 {
150 #if defined(DEBUG) && defined(METAWARE)
151 log_printf("KMSClient_InitializeLibrary : check working directory");
152 #endif
153
154 // string is there but is empty or junk
155 if (strlen(i_wsWorkingDirectory) <= 0)
156 {
157 strcpy(i_wsWorkingDirectory, ".");
158 }
159
160 if ( strlen(i_wsWorkingDirectory) >= KMS_MAX_PATH_LENGTH )
161 {
162 return false;
163 }
164
165 #if defined(DEBUG) && defined(METAWARE)
166 log_printf("KMSClient_InitializeLibrary : set global working directory");
167 #endif
168
169 // set global working directory to input
170 strncpy(g_wsWorkingDirectory,
171 i_wsWorkingDirectory,
172 KMS_MAX_PATH_LENGTH);
173 g_wsWorkingDirectory[KMS_MAX_PATH_LENGTH] = 0;
174 }
175 else
176 {
177 strcpy(g_wsWorkingDirectory, ".");
178 }
179
180 #if defined(DEBUG) && defined(METAWARE)
181 log_printf("KMSClient_InitializeLibrary : Initialize logging");
182 #endif
183
184 // initialize file logging
185 bSuccess = InitializeLogging( g_wsWorkingDirectory,
186 i_bUseFileLog);
187
188 return bSuccess;
189 }
190
191
192 /*---------------------------------------------------------------------------
193 * Function: KMSClient_FinalizeLibrary
194 *--------------------------------------------------------------------------*/
KMSClient_FinalizeLibrary()195 bool KMSClient_FinalizeLibrary()
196 {
197 #if defined(DEBUG) && defined(METAWARE)
198 log_printf("KMSClient_FinalizeLibrary : ENTERING");
199 #endif
200
201 K_CleanupSSL();
202
203 FinalizeLogging();
204
205 return true; /* always */
206 }
207
208
209 int LogError_lastErrno;
210
211
212 /**
213 * Construct a message for the KMSAuditLogger and store the message
214 * in the profile as the last error message.
215 */
LogError_function(KMSClientProfile * i_pProfile,int i_iErrno,const char * i_sOperation,const char * i_sEntityID,const char * i_sNetworkAddress,const char * i_sMessage)216 void LogError_function(KMSClientProfile *i_pProfile,
217 int i_iErrno,
218 const char* i_sOperation,
219 const char* i_sEntityID,
220 const char* i_sNetworkAddress,
221 const char* i_sMessage )
222 {
223 FATAL_ASSERT( i_pProfile && i_sOperation );
224
225 // save for caller's use - this shouldn't be a global, but I don't
226 // want this as an item in the profile as I don't want it persisted
227 LogError_lastErrno = i_iErrno;
228
229 // log the message to a data file (and internal logs)
230 #ifndef METAWARE
231 if ( g_bUseFileLog )
232 #endif
233 {
234 Log_function(i_iErrno,
235 i_sOperation,
236 i_sEntityID,
237 i_sNetworkAddress,
238 i_sMessage);
239 }
240
241 #ifdef METAWARE
242 /* print this to the T10000/9840 VOP */
243 /* NOTE the \n is important to VOP - leave it in */
244 tnMsg("`msg`KMS2.0:msg#=%i,op=%s\r\n",
245 i_iErrno,
246 i_sOperation);
247
248 tnMsg("`msg`msg=%s,eid=%s,addr=%s\r\n",
249 i_sMessage,
250 i_sEntityID,
251 i_sNetworkAddress);
252
253 #endif
254
255 // copy the error message into the profile (for later reference)
256 strncpy(i_pProfile->m_wsErrorString,
257 i_sOperation,
258 KMS_MAX_ERROR_STRING);
259
260 // make sure to NUL out the end
261 i_pProfile->m_wsErrorString[KMS_MAX_ERROR_STRING] = 0;
262
263 if ( i_sEntityID )
264 {
265 strncat(i_pProfile->m_wsErrorString,
266 i_sEntityID,
267 KMS_MAX_ERROR_STRING);
268 }
269
270 if ( i_sNetworkAddress )
271 {
272 strncat(i_pProfile->m_wsErrorString,
273 ",Address=",
274 KMS_MAX_ERROR_STRING);
275 strncat(i_pProfile->m_wsErrorString,
276 i_sNetworkAddress,
277 KMS_MAX_ERROR_STRING);
278 }
279
280 if ( i_sMessage )
281 {
282 strncat(i_pProfile->m_wsErrorString,
283 ",Msg=",
284 KMS_MAX_ERROR_STRING);
285 strncat(i_pProfile->m_wsErrorString,
286 i_sMessage,
287 KMS_MAX_ERROR_STRING);
288 }
289
290 // make sure to NUL out the end
291 i_pProfile->m_wsErrorString[KMS_MAX_ERROR_STRING] = 0;
292
293 }
294
295 // see KMSClientProfileImpl.h
SSL_InvalidCertificate(const char * const i_sErrorString)296 bool SSL_InvalidCertificate (const char * const i_sErrorString)
297 {
298 if (
299 // OpenSSL generates this msg
300 strstr(i_sErrorString, "sslv3 alert certificate unknown"))
301 {
302 return true;
303 }
304 return false;
305
306 }
307
308 // see KMSClientProfileImpl.h
ServerError(const char * i_sErrorString,int i_iErrno)309 bool ServerError (const char * i_sErrorString, int i_iErrno )
310 {
311 // The Client Soap Fault Code returned by the KMA
312 // may be at the start of i_sErrorString or immediately
313 // follwing "SoapFaultString=" depending on the caller's
314 // string
315
316 int iErrorCode;
317
318 const char* sFaultstringStart = strstr(i_sErrorString, "SoapFaultString=" );
319 if ( sFaultstringStart )
320 {
321 iErrorCode = GET_FAULT_CODE( sFaultstringStart + strlen("SoapFaultString=") );
322 }
323 else
324 {
325 // This may be zero if there is no error code at the start of the string.
326 iErrorCode = GET_FAULT_CODE( i_sErrorString );
327 }
328
329 // the following is commented out so the former check can be observed. This check is no longer
330 // made since invalid certificate failures may be due to a KMA that is behind on
331 // replication updates hence failover would succeed.
332 // if (
333 // // OpenSSL generates this msg
334 // SSL_InvalidCertificate(i_sErrorString))
335 // {
336 // return false;
337 // }
338
339 if (
340 // when the KMA is locked
341 iErrorCode == CLIENT_ERROR_AGENT_APPLIANCE_LOCKED
342
343 // KMS 2.2 change when the KMA is locked
344 || iErrorCode == CLIENT_ERROR_MANAGER_APPLIANCE_LOCKED
345
346 // KMS 2.2 change for core security internal error
347 || iErrorCode == CLIENT_ERROR_MANAGER_INTERNAL
348
349 // if the KMA's pre-gen'd key pool is depleted
350 || iErrorCode == CLIENT_ERROR_AGENT_NO_READY_KEYS
351
352 // if the KMA's HSM is broke and the KMA is in FIPS mode
353 || iErrorCode == CLIENT_ERROR_SERVER_HSM_REQUIRED_BUT_MISSING
354
355 // when the server is too slow
356 || NULL != strstr( i_sErrorString, "Timeout" )
357 || NULL != strstr( i_sErrorString, "Operation interrupted or timed out" )
358
359 // The Appliance is powered down, or is not reachable
360 || NULL != strstr( i_sErrorString, "Connection refused" )
361
362 || NULL != strstr( i_sErrorString, "Unknown error" )
363
364 // SOAP EOF
365 || NULL != strstr( i_sErrorString, "End of file or no input:" )
366
367 // Appliance server software is not running (while Appliance machine is OK)
368 || NULL != strstr( i_sErrorString, "connect failed in tcp_connect()" )
369
370 // If the server has an internal error but still responds
371 || NULL != strstr( i_sErrorString, "Server Error" )
372
373 // OpenSSL protocol errors (Note: the SSL_ERROR_SSL may be due
374 // to invalid client-side values, but for now it's used as a
375 // catch-all; a side-effect is that any actual invalid client-side
376 // value will cause one audit log entry to be created on each
377 // Appliance in the cluster).
378 || NULL != strstr( i_sErrorString,
379 "Error observed by underlying BIO: No error" )
380 || NULL != strstr( i_sErrorString,
381 "EOF was observed that violates the protocol" )
382 || NULL != strstr( i_sErrorString,
383 "SSL_ERROR_SSL" ) )
384 {
385 return true;
386 }
387
388 #ifndef WIN32
389 // check for errno values that imply connection problems to the server
390 switch (i_iErrno)
391 {
392 case ECONNABORTED : return true; // Connection aborted.
393 case ECONNREFUSED : return true; // Connection refused.
394 case ECONNRESET : return true; // Connection reset.
395 case EHOSTUNREACH : return true; // Host is unreachable.
396 case ENETDOWN : return true; // Network is down.
397 case ENETRESET : return true; // Connection aborted by network.
398 case ENETUNREACH : return true; // Network unreachable.
399 case ENOPROTOOPT : return true; // Protocol not available.
400 #ifndef METAWARE
401 case ETIME : return true; // Stream ioctl() timeout.
402 #endif
403 case ETIMEDOUT : return true; // Connection timed out.
404 }
405 #endif
406 // at this point we conclude its a client side issue
407 return false;
408 }
409
410 /*---------------------------------------------------------------------------
411 * Function: KMSClient_GetLastErrorMessage
412 *
413 *--------------------------------------------------------------------------*/
414
415 // extern "C"
KMSClient_GetLastErrorMessage(KMSClientProfile * i_pProfile)416 utf8char * KMSClient_GetLastErrorMessage(KMSClientProfile *i_pProfile)
417 {
418 FATAL_ASSERT(i_pProfile);
419
420 CAutoMutex oAutoMutex( 0 );
421 if ( i_pProfile->m_pLock )
422 {
423 oAutoMutex.Lock( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
424 }
425
426 return i_pProfile->m_wsErrorString;
427 }
428
429
430 /*---------------------------------------------------------------------------
431 * Function: KMSClient_RetrieveEntityCertificate
432 * Get the Root CA Certificate and store it into the profile
433 *--------------------------------------------------------------------------*/
KMSClient_RetrieveEntityCertificate(KMSClientProfile * i_pProfile,utf8cstr i_wsEntityID,utf8cstr i_wsPassphrase,char * const o_sHexHashedPassphrase)434 static bool KMSClient_RetrieveEntityCertificate(
435 KMSClientProfile* i_pProfile,
436 utf8cstr i_wsEntityID,
437 utf8cstr i_wsPassphrase,
438 char* const o_sHexHashedPassphrase )
439 {
440 FATAL_ASSERT( i_pProfile && i_wsEntityID && i_wsPassphrase );
441
442 #if defined(DEBUG) && defined(METAWARE)
443 log_printf("KMSClient_RetrieveEntityCertificate : entered");
444 #endif
445
446 CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
447 char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
448 char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
449
450 strcpy(o_sHexHashedPassphrase, "");
451
452 bool bSuccess = true;
453 bool bTryFailOver = false;
454
455 struct soap *pstCASoap;
456 pstCASoap = (struct soap *) malloc( sizeof(struct soap) );
457 if(pstCASoap == NULL)
458 {
459 #if defined(DEBUG) && defined(METAWARE)
460 log_printf("Malloc %x pstCASoap returned null\n", sizeof(struct soap));
461 #endif
462 LogError(i_pProfile,
463 LoadProfile_AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SOAP_ERROR,
464 NULL,
465 NULL,
466 "malloc failure for pstCASoap" );
467 return false;
468 }
469
470 // initialize the SOAP connection that will get the RootCA
471 soap_init2( pstCASoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
472
473 #ifdef METAWARE
474 K_SetupCallbacks ( pstCASoap );
475 #endif
476
477 CCertificate* pRootCACertificate = 0;
478 CCertificate* pEntityCertificate = 0;
479 CPrivateKey* pEntityPrivateKey = 0;
480
481 soap_set_namespaces( pstCASoap, KMS_CA_namespaces );
482
483 pstCASoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
484 pstCASoap->send_timeout = i_pProfile->m_iTransactionTimeout;
485 pstCASoap->recv_timeout = i_pProfile->m_iTransactionTimeout;
486
487 struct soap *pstCertificateSoap;
488
489 pstCertificateSoap = (struct soap *) malloc( sizeof(struct soap) );
490
491 if(pstCertificateSoap == NULL)
492 {
493 #if defined(METAWARE)
494 log_printf("Malloc %x pstCertificateSoap returned null\n",
495 sizeof(struct soap));
496 #endif
497 soap_free( pstCASoap );
498 free(pstCASoap);
499 return false;
500 }
501
502 // initialize the SOAP connection that will get the Certificate
503 soap_init2( pstCertificateSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
504
505 #ifdef METAWARE
506 K_SetupCallbacks ( pstCertificateSoap );
507 #endif
508
509 soap_set_namespaces( pstCertificateSoap, KMS_Certificate_namespaces );
510
511 pstCertificateSoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
512 pstCertificateSoap->send_timeout = i_pProfile->m_iTransactionTimeout;
513 pstCertificateSoap->recv_timeout = i_pProfile->m_iTransactionTimeout;
514
515 CAgentLoadBalancer oLoadBalancer(i_pProfile);
516 int iIndex = oLoadBalancer.Balance();
517
518 #if defined(DEBUG) && defined(METAWARE)
519 log_printf("KMSClient_RetrieveEntityCertificate : call KMS_CA__RetrieveRootCACertificate");
520 #endif
521
522 // get the server's URL that will provide SOAP services
523 do
524 {
525 bSuccess = true;
526 bTryFailOver = false;
527 bool bFailedOnRetrieveRootCA = false;
528 const char* sURL = 0;
529
530 if ( bSuccess )
531 {
532 sURL = oLoadBalancer.GetHTTPURL(iIndex,
533 i_pProfile->m_iPortForCAService);
534
535 if ( !sURL )
536 {
537 bSuccess = false;
538 }
539 }
540
541 if ( bSuccess )
542 {
543 strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
544 i_pProfile->m_sURL[KMS_MAX_URL] = 0;
545 }
546
547
548 // SOAP CALL - retrieve Root CA Certificate from the Server
549 struct KMS_CA::
550 KMS_CA__RetrieveRootCACertificateResponse stRootCACertificateResponse;
551
552 if ( bSuccess )
553 {
554 #if defined(DEBUG) && defined(METAWARE)
555 log_printf("KMSClient_RetrieveCertificate : call KMS_CA__RetrieveRootCACertificate again");
556 #endif
557 bSuccess =
558 KMS_CA::soap_call_KMS_CA__RetrieveRootCACertificate(
559 pstCASoap,
560 i_pProfile->m_sURL,
561 NULL,
562 i_wsEntityID,
563 stRootCACertificateResponse ) == SOAP_OK;
564
565 if ( !bSuccess )
566 {
567 GetSoapFault(sSoapFaultMsg, (struct soap*)pstCASoap);
568 GetPeerNetworkAddress(sKmaAddress, pstCASoap);
569 LogError(i_pProfile,
570 LoadProfile_AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SOAP_ERROR,
571 NULL,
572 sKmaAddress,
573 sSoapFaultMsg );
574
575 bTryFailOver = ServerError(GET_SOAP_FAULTSTRING(pstCASoap), pstCASoap->errnum);
576 bFailedOnRetrieveRootCA = true;
577 }
578 }
579 #if defined(DEBUG) && defined(METAWARE)
580 else
581 {
582 log_printf("!bSuccess 1\n");
583 }
584 #endif
585
586
587 // Validate the SOAP response
588 if ( bSuccess )
589 {
590 if ( stRootCACertificateResponse.RootCACertificate.__size < 1 ||
591 stRootCACertificateResponse.RootCACertificate.__ptr == NULL ||
592 stRootCACertificateResponse.AuthenticationHashIterationCount <
593 MIN_AUTHENTICATION_ITERATION_COUNT ||
594 stRootCACertificateResponse.AuthenticationHashIterationCount >
595 MAX_AUTHENTICATION_ITERATION_COUNT ||
596 stRootCACertificateResponse.ClientAuthenticationChallenge.__size !=
597 AUTHENTICATION_CHALLENGE_LENGTH ||
598 stRootCACertificateResponse.ClientAuthenticationChallenge.__ptr == NULL )
599 {
600 bSuccess = false;
601
602 GetPeerNetworkAddress(sKmaAddress, pstCASoap);
603 LogError(i_pProfile,
604 AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_INVALID_RESPONSE_FORMAT,
605 NULL,
606 sKmaAddress,
607 NULL);
608 }
609 else
610 {
611 GetPeerNetworkAddress(sKmaAddress, pstCASoap);
612 Log(AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SUCCESS,
613 NULL,
614 sKmaAddress,
615 NULL);
616 }
617
618 }
619 #if defined(DEBUG) && defined(METAWARE)
620 else
621 {
622 log_printf("!bSuccess 2\n");
623 }
624 #endif
625
626 // build our RootCACertificate object
627 if ( bSuccess )
628 {
629 pRootCACertificate = new CCertificate;
630
631 // make sure the new was successful
632 bSuccess = ( pRootCACertificate != 0 );
633 }
634 #if defined(DEBUG) && defined(METAWARE)
635 else
636 {
637 log_printf("!bSuccess 3\n");
638 }
639 #endif
640
641 if ( bSuccess )
642 {
643 // OVERLOADED Load method - 3 parameters means
644 // recall from BUFFER
645 bSuccess =
646 pRootCACertificate->Load(
647 stRootCACertificateResponse.RootCACertificate.__ptr, // to here
648 stRootCACertificateResponse.RootCACertificate.__size, // size
649 PKI_FORMAT ); // ignored
650
651 if( !bSuccess )
652 {
653 GetPeerNetworkAddress(sKmaAddress, pstCASoap);
654 LogError(i_pProfile,
655 AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_INVALID_CA_CERTIFICATE_FORMAT,
656 NULL,
657 sKmaAddress,
658 NULL);
659 }
660
661 }
662 #if defined(DEBUG) && defined(METAWARE)
663 else
664 {
665 log_printf("!bSuccess 4\n");
666 }
667 #endif
668
669
670 if ( bSuccess )
671 {
672 // save the built CACertificate object to a FILE (i_pProfile gets the
673 // persistent handle to that file)
674 bSuccess = StoreCACertificate( i_pProfile, pRootCACertificate );
675
676 if ( !bSuccess )
677 {
678 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SAVE_CA_CERTIFICATE_FAILED,
679 NULL,
680 NULL,
681 NULL);
682 }
683 }
684 #if defined(DEBUG) && defined(METAWARE)
685 else
686 {
687 log_printf("!bSuccess 5\n");
688 }
689 #endif
690
691 //-------------------------------
692 // Initialize SSL - use SERVER AUTH
693 //-------------------------------
694 if ( bSuccess )
695 {
696 // SERVER_AUTHENTICATION needs just the pstCertificateSoap
697 bSuccess =
698 K_soap_ssl_client_context(
699 i_pProfile, // in ->m_wsProfileName,->m_sHexHashedPassphrase
700 pstCertificateSoap, // in - soap structure
701 SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION // in - flags
702 ) == SOAP_OK;
703
704 if ( !bSuccess )
705 {
706 GetSoapFault(sSoapFaultMsg, (struct soap*)pstCertificateSoap);
707 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
708 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SOAP_ERROR,
709 NULL,
710 sKmaAddress,
711 sSoapFaultMsg );
712 }
713 }
714 #if defined(DEBUG) && defined(METAWARE)
715 else
716 {
717 log_printf("!bSuccess 6\n");
718 }
719 #endif
720
721 // hash the passphrase passed in
722 char sHexAuthenticationSecret[2*HASH_LENGTH+1];
723
724 if ( bSuccess )
725 {
726 bSuccess = ComputeFixedEntityHashedPassphraseAndAuthenticationSecret(
727 i_wsPassphrase,
728 o_sHexHashedPassphrase,
729 stRootCACertificateResponse.AuthenticationHashIterationCount,
730 sHexAuthenticationSecret );
731
732 if ( !bSuccess )
733 {
734 LogError(i_pProfile,AUDIT_CLIENT_COMPUTE_FIXED_FAILED,
735 NULL,
736 NULL,
737 NULL);
738 }
739 }
740 #if defined(DEBUG) && defined(METAWARE)
741 else
742 {
743 log_printf("!bSuccess 7\n");
744 }
745 #endif
746
747 // copy received Root CA into buffer for input
748 // into challenge-response computation
749 unsigned char aRootCACertificate[MAX_CERT_SIZE];
750 int iRootCACertificateLength;
751
752 if ( bSuccess )
753 {
754 // OVERLOADED save method - save iRootCACertificateLength to aRootCACertificate
755 // buffer
756 bSuccess = pRootCACertificate->Save(
757 aRootCACertificate,
758 MAX_CERT_SIZE,
759 &iRootCACertificateLength,
760 PKI_FORMAT );
761
762 if ( !bSuccess )
763 {
764 LogError(i_pProfile,AUDIT_CLIENT_SAVE_ROOTCA_FAILED,
765 NULL,
766 NULL,
767 NULL);
768 }
769 }
770 #if defined(DEBUG) && defined(METAWARE)
771 else
772 {
773 log_printf("!bSuccess 8\n");
774 }
775 #endif
776
777 // respond to server's challenge
778 unsigned char aAuthenticationSecret[AUTHENTICATION_SECRET_LENGTH];
779 unsigned char
780 aClientAuthenticationChallengeResponse[AUTHENTICATION_RESPONSE_LENGTH];
781
782 if ( bSuccess )
783 {
784 FATAL_ASSERT( AUTHENTICATION_SECRET_LENGTH ==
785 ConvertUTF8HexStringToBinary(
786 sHexAuthenticationSecret, NULL ) );
787
788 ConvertUTF8HexStringToBinary(
789 sHexAuthenticationSecret, aAuthenticationSecret );
790
791 // client authentication response
792 bSuccess = ComputeChallengeResponse(
793 aAuthenticationSecret,
794 AUTHENTICATION_SECRET_LENGTH,
795 aRootCACertificate,
796 iRootCACertificateLength,
797 stRootCACertificateResponse.ClientAuthenticationChallenge.__ptr,
798 AUTHENTICATION_CHALLENGE_LENGTH,
799 aClientAuthenticationChallengeResponse,
800 AUTHENTICATION_RESPONSE_LENGTH );
801
802 if ( !bSuccess )
803 {
804 LogError(i_pProfile,AUDIT_CLIENT_COMPUTE_CHALLENGE_RESPONSE_FAILED,
805 NULL,
806 NULL,
807 NULL);
808 }
809 }
810 #if defined(DEBUG) && defined(METAWARE)
811 else
812 {
813 log_printf("!bSuccess 9\n");
814 }
815 #endif
816
817 struct KMS_Certificate::xsd__hexBinary stClientAuthenticationResponse;
818
819 if ( bSuccess )
820 {
821 stClientAuthenticationResponse.__size =
822 AUTHENTICATION_RESPONSE_LENGTH;
823 stClientAuthenticationResponse.__ptr =
824 (unsigned char*)soap_malloc(
825 pstCertificateSoap, AUTHENTICATION_RESPONSE_LENGTH );
826
827 if ( stClientAuthenticationResponse.__ptr != NULL )
828 {
829 memcpy( stClientAuthenticationResponse.__ptr,
830 aClientAuthenticationChallengeResponse,
831 AUTHENTICATION_RESPONSE_LENGTH );
832 }
833 else
834 {
835 bSuccess = false;
836 }
837 }
838 #if defined(DEBUG) && defined(METAWARE)
839 else
840 {
841 log_printf("!bSuccess 10\n");
842 }
843 #endif
844
845 // generate challenge nonce
846 struct KMS_Certificate::xsd__hexBinary stServerAuthenticationChallenge;
847
848 if ( bSuccess )
849 {
850 stServerAuthenticationChallenge.__size =
851 AUTHENTICATION_CHALLENGE_LENGTH;
852 stServerAuthenticationChallenge.__ptr =
853 (unsigned char*)soap_malloc( pstCertificateSoap,
854 AUTHENTICATION_CHALLENGE_LENGTH );
855
856 bSuccess = ( stServerAuthenticationChallenge.__ptr != NULL );
857 }
858 #if defined(DEBUG) && defined(METAWARE)
859 else
860 {
861 log_printf("!bSuccess 11\n");
862 }
863 #endif
864
865 if ( bSuccess )
866 {
867 bSuccess = GetPseudorandomBytes(
868 AUTHENTICATION_CHALLENGE_LENGTH,
869 stServerAuthenticationChallenge.__ptr );
870 }
871 #if defined(DEBUG) && defined(METAWARE)
872 else
873 {
874 log_printf("!bSuccess 12\n");
875 }
876 #endif
877
878 if ( bSuccess )
879 {
880 sURL = oLoadBalancer.GetHTTPSURL(iIndex,
881 i_pProfile->
882 m_iPortForCertificateService);
883
884 if ( !sURL )
885 {
886 bSuccess = false;
887 }
888 }
889 #if defined(DEBUG) && defined(METAWARE)
890 else
891 {
892 log_printf("!bSuccess 13\n");
893 }
894 #endif
895
896 // Verify that the same URL is used for Root CA Certificate
897 // retrieval as for Entity Certificate retrieval
898
899 if ( bSuccess )
900 {
901 char sTempCAURL[KMS_MAX_URL + 1];
902 strncpy( sTempCAURL, i_pProfile->m_sURL, KMS_MAX_URL );
903 sTempCAURL[KMS_MAX_URL] = 0;
904
905 char * sRetrieveRootCACertificateURL = strtok( sTempCAURL, ":" );
906
907 sRetrieveRootCACertificateURL = strtok(NULL, ":");
908
909 char sTempAgentURL[KMS_MAX_URL + 1];
910 strncpy( sTempAgentURL, sURL, KMS_MAX_URL );
911 sTempAgentURL[KMS_MAX_URL] = 0;
912 char * sRetrieveAgentCertificateURL = strtok( sTempAgentURL, ":" );
913 sRetrieveAgentCertificateURL = strtok(NULL, ":");
914
915 FATAL_ASSERT( strcmp( sRetrieveRootCACertificateURL,
916 sRetrieveAgentCertificateURL ) == 0 );
917
918 strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
919 i_pProfile->m_sURL[KMS_MAX_URL] = 0;
920 }
921 #if defined(DEBUG) && defined(METAWARE)
922 else
923 {
924 log_printf("!bSuccess 14\n");
925 }
926 #endif
927
928 KMS_Certificate::KMS_Certificate__RetrieveEntityCertificateResponse
929 stRetrieveEntityCertificateResponse;
930
931 // SOAP - retrieve ENTITY Certificate, passing the challenge response,
932 // a challenge to the server and get back the server's response
933 if ( bSuccess )
934 {
935 bSuccess =
936 KMS_Certificate::soap_call_KMS_Certificate__RetrieveEntityCertificate(
937 pstCertificateSoap,
938 sURL,
939 NULL,
940 (utf8cstr )i_wsEntityID,
941 stClientAuthenticationResponse,
942 stServerAuthenticationChallenge,
943 stRetrieveEntityCertificateResponse ) == SOAP_OK;
944
945 if( !bSuccess )
946 {
947 GetSoapFault(sSoapFaultMsg, (struct soap*)pstCertificateSoap);
948 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
949 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SOAP_ERROR,
950 NULL,
951 sKmaAddress,
952 sSoapFaultMsg );
953
954 bTryFailOver = ServerError(GET_SOAP_FAULTSTRING(pstCertificateSoap),
955 pstCertificateSoap->errnum);
956 }
957 }
958 #if defined(DEBUG) && defined(METAWARE)
959 else
960 {
961 log_printf("!bSuccess 15\n");
962 }
963 #endif
964
965 // Validate the response structure
966 if ( bSuccess )
967 {
968 if ( stRetrieveEntityCertificateResponse.
969 ServerAuthenticationResponse.__ptr == NULL
970
971 || stRetrieveEntityCertificateResponse.
972 ServerAuthenticationResponse.__size !=
973 AUTHENTICATION_RESPONSE_LENGTH
974
975 || stRetrieveEntityCertificateResponse.Certificate.__size < 1
976
977 || stRetrieveEntityCertificateResponse.Certificate.__ptr == 0
978
979 || stRetrieveEntityCertificateResponse.
980 WrappedPrivateKeyMaterial.__size < 1
981
982 || stRetrieveEntityCertificateResponse.
983 WrappedPrivateKeyMaterial.__ptr == 0 )
984 {
985 bSuccess = false;
986
987 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
988 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_RESPONSE_FORMAT,
989 NULL,
990 sKmaAddress,
991 NULL );
992 }
993 else
994 {
995 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
996 Log(AUDIT_CLIENT_GET_CERTIFICATE_SUCCESS,
997 NULL,
998 sKmaAddress,
999 NULL );
1000 }
1001 }
1002 #if defined(DEBUG) && defined(METAWARE)
1003 else
1004 {
1005 log_printf("!bSuccess 16\n");
1006 }
1007 #endif
1008
1009 // if valid, calculate the correct challenge-response
1010 unsigned char
1011 aServerAuthenticationChallengeResponse[AUTHENTICATION_RESPONSE_LENGTH];
1012
1013 if ( bSuccess )
1014 {
1015 bSuccess = ComputeChallengeResponse(
1016 aAuthenticationSecret,
1017 AUTHENTICATION_SECRET_LENGTH,
1018 aRootCACertificate,
1019 iRootCACertificateLength,
1020 stServerAuthenticationChallenge.__ptr,
1021 AUTHENTICATION_CHALLENGE_LENGTH,
1022 aServerAuthenticationChallengeResponse,
1023 AUTHENTICATION_RESPONSE_LENGTH );
1024 }
1025 #if defined(DEBUG) && defined(METAWARE)
1026 else
1027 {
1028 log_printf("!bSuccess 17\n");
1029 }
1030 #endif
1031
1032 // if successful, check if the server provided the correct challenge-response
1033 if ( bSuccess )
1034 {
1035 if ( 0 != memcmp(
1036 aServerAuthenticationChallengeResponse,
1037 stRetrieveEntityCertificateResponse.ServerAuthenticationResponse.__ptr,
1038 AUTHENTICATION_RESPONSE_LENGTH ) )
1039 {
1040 bSuccess = false;
1041
1042 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1043 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_CHALLENGE_RESPONSE,
1044 NULL,
1045 sKmaAddress,
1046 NULL );
1047 }
1048 }
1049 #if defined(DEBUG) && defined(METAWARE)
1050 else
1051 {
1052 log_printf("!bSuccess 18\n");
1053 }
1054 #endif
1055
1056
1057 if ( bSuccess )
1058 {
1059 pEntityCertificate = new CCertificate;
1060 // if certificate was obtained
1061 bSuccess = ( pEntityCertificate != 0 );
1062 }
1063 #if defined(DEBUG) && defined(METAWARE)
1064 else
1065 {
1066 log_printf("!bSuccess 19\n");
1067 }
1068 #endif
1069
1070 if ( bSuccess )
1071 {
1072 // Load(recall) the signed certificate using OVERLOADED load method
1073 // 3 parameters means load from a buffer
1074 bSuccess = pEntityCertificate->Load(
1075 stRetrieveEntityCertificateResponse.Certificate.__ptr, // load into
1076 stRetrieveEntityCertificateResponse.Certificate.__size,
1077 PKI_FORMAT );
1078
1079 if ( !bSuccess )
1080 {
1081 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1082 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_CERTIFICATE_FORMAT,
1083 NULL,
1084 sKmaAddress,
1085 NULL );
1086 }
1087 }
1088 #if defined(DEBUG) && defined(METAWARE)
1089 else
1090 {
1091 log_printf("!bSuccess 20\n");
1092 }
1093 #endif
1094
1095 if ( bSuccess )
1096 {
1097 pEntityPrivateKey = new CPrivateKey;
1098 bSuccess = ( pEntityPrivateKey != 0 );
1099 }
1100 #if defined(DEBUG) && defined(METAWARE)
1101 else
1102 {
1103 log_printf("!bSuccess 21\n");
1104 }
1105 #endif
1106
1107
1108 if ( bSuccess )
1109 {
1110 // Load the Private Key using OVERLOADED Load method - 3 parameters
1111 // means load from a buffer
1112
1113 // TODO: change this when certificate service supports requesting unwrapped private keys
1114 bSuccess = pEntityPrivateKey->Load(
1115 stRetrieveEntityCertificateResponse.WrappedPrivateKeyMaterial.__ptr, // load into
1116 stRetrieveEntityCertificateResponse.WrappedPrivateKeyMaterial.__size,
1117 NULL,
1118 PKI_FORMAT );
1119
1120 if (!bSuccess )
1121 {
1122
1123 GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1124 LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_KEY_FORMAT,
1125 NULL,
1126 sKmaAddress,
1127 NULL );
1128 }
1129 }
1130
1131 if ( bSuccess )
1132 {
1133 strncpy(i_pProfile->m_wsEntityID,
1134 i_wsEntityID,
1135 KMS_MAX_ENTITY_ID );
1136 i_pProfile->m_wsEntityID[KMS_MAX_ENTITY_ID] = 0;
1137
1138 // store PKI certificates and unwrapped private key
1139 bSuccess = StorePKIcerts( i_pProfile,
1140 pRootCACertificate,
1141 pEntityCertificate,
1142 pEntityPrivateKey,
1143 #ifdef KMSUSERPKCS12
1144 i_wsPassphrase
1145 #else
1146 NULL
1147 #endif
1148 );
1149 #ifdef KMSUSERPKCS12
1150 if (bSuccess) {
1151 /*
1152 * Write out the cert and key individually so GetPKIcerts
1153 * can use them.
1154 */
1155 bSuccess = StoreTempAgentPKI(i_pProfile,
1156 pEntityCertificate, pEntityPrivateKey);
1157 }
1158
1159 #endif
1160 }
1161
1162 if ( !bSuccess )
1163 {
1164 if (pRootCACertificate)
1165 {
1166 delete pRootCACertificate;
1167 }
1168 if (pEntityCertificate)
1169 {
1170 delete pEntityCertificate;
1171 }
1172 if (pEntityPrivateKey)
1173 {
1174 delete pEntityPrivateKey;
1175 }
1176
1177 i_pProfile->m_iEnrolled = FALSE;
1178
1179 if ( bTryFailOver )
1180 {
1181 iIndex = oLoadBalancer.FailOver(iIndex, bFailedOnRetrieveRootCA ? pstCASoap : pstCertificateSoap);
1182 }
1183 }
1184 }
1185 while ( bTryFailOver && (iIndex >= 0) && !bSuccess );
1186
1187 // certs are now persisted so free up space
1188 if ( bSuccess )
1189 {
1190 delete pRootCACertificate;
1191 delete pEntityCertificate;
1192 delete pEntityPrivateKey;
1193 }
1194
1195 // Clean up SOAP resources for pstCASoap
1196 soap_destroy( pstCASoap );
1197 soap_end( pstCASoap );
1198 soap_done( pstCASoap );
1199
1200 // Clean up SOAP resources for pstCertificateSoap
1201 soap_destroy( pstCertificateSoap );
1202 soap_end( pstCertificateSoap );
1203 soap_done( pstCertificateSoap );
1204
1205 free(pstCASoap);
1206 free(pstCertificateSoap);
1207
1208 return bSuccess;
1209 }
1210
1211 /*--------------------------------------------------------------------------
1212 * LoadClusterInformation
1213 * calls GetCluster - that's it.
1214 * If there is no cluster file, this function will return true,
1215 * but o_bClusterInformationFound will be false.
1216 *-------------------------------------------------------------------------*/
LoadClusterInformation(KMSClientProfile * i_pProfile,int & o_bClusterInformationFound)1217 static bool LoadClusterInformation( KMSClientProfile* i_pProfile,
1218 int& o_bClusterInformationFound )
1219 {
1220 FATAL_ASSERT( i_pProfile );
1221
1222 o_bClusterInformationFound = false;
1223
1224 CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
1225
1226 return GetCluster( i_pProfile, o_bClusterInformationFound ) ;
1227
1228 }
1229
1230
1231 /*--------------------------------------------------------------------------
1232 * EnrollAgent
1233 * calls functions to perform enrollment and save PKI info to persistent storage
1234 * stores configuration in persistent storage
1235 *-------------------------------------------------------------------------*/
1236
EnrollAgent(KMSClientProfile * io_pProfile,utf8cstr i_wsEntityID,utf8cstr i_wsPassphrase)1237 static bool EnrollAgent( KMSClientProfile * io_pProfile,
1238 utf8cstr i_wsEntityID,
1239 utf8cstr i_wsPassphrase )
1240 {
1241 FATAL_ASSERT( io_pProfile && i_wsEntityID && i_wsPassphrase );
1242
1243 bool bSuccess = true;
1244
1245 // see KMSAgentCryptoUtilities for HASH_LENGTH, aka KMS_MAX_HASH_SIZE
1246 char sHexHashedPassphrase[2*KMS_MAX_HASH_SIZE+1];
1247
1248 if ( bSuccess )
1249 {
1250 // performs enrollment and saves PKI info to persistent storage
1251 bSuccess = KMSClient_RetrieveEntityCertificate(
1252 io_pProfile,
1253 i_wsEntityID,
1254 i_wsPassphrase,
1255 sHexHashedPassphrase );
1256
1257 // KMSClient_RetrieveCertificate logs errors
1258 }
1259
1260 if (bSuccess)
1261 {
1262 strncpy(io_pProfile->m_sHexHashedPassphrase,
1263 sHexHashedPassphrase,
1264 2*KMS_MAX_HASH_SIZE );
1265 io_pProfile->m_sHexHashedPassphrase[2*KMS_MAX_HASH_SIZE] = 0;
1266
1267 // persist the profile now updated with the hashed passphrase
1268 bSuccess = StoreConfig( io_pProfile );
1269
1270 if (!bSuccess)
1271 {
1272 Log(AUDIT_CLIENT_LOAD_PROFILE,
1273 i_wsEntityID,
1274 NULL,
1275 "store config failed following enrollment" );
1276 }
1277 }
1278
1279 return bSuccess;
1280 }
1281
1282 /*---------------------------------------------------------------------------
1283 * Function: KMSClient_LoadProfile
1284 *
1285 *--------------------------------------------------------------------------*/
KMSClient_LoadProfile(KMSClientProfile * io_pProfile,utf8char * i_wsProfileName,utf8char * i_wsEntityID,utf8char * i_wsPassphrase,utf8char * i_wsApplianceAddress,int i_iTransactionTimeout,int i_iFailOverLimit,int i_iClusterDiscoveryFrequency,int i_eKMSmode)1286 bool KMSClient_LoadProfile(
1287 KMSClientProfile *io_pProfile,
1288 utf8char *i_wsProfileName,
1289 utf8char *i_wsEntityID,
1290 utf8char *i_wsPassphrase,
1291 utf8char *i_wsApplianceAddress,
1292 int i_iTransactionTimeout,
1293 int i_iFailOverLimit,
1294 int i_iClusterDiscoveryFrequency,
1295 int i_eKMSmode)
1296 {
1297 FATAL_ASSERT(io_pProfile);
1298 FATAL_ASSERT(i_wsProfileName);
1299
1300 bool bSuccess = true;
1301
1302 char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
1303 char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
1304
1305 #if defined(DEBUG) && defined(METAWARE)
1306 log_printf("KMSClient_LoadProfile : entered");
1307 #endif
1308
1309 memset( io_pProfile, 0, sizeof(KMSClientProfile) );
1310
1311 // create lock
1312
1313 if (bSuccess)
1314 {
1315 bSuccess =
1316 ( K_CreateMutex((K_MUTEX_HANDLE *)&io_pProfile->m_pLock) ==
1317 K_SYS_OK );
1318 }
1319
1320 // initialize profile with parameters
1321
1322 strncpy(io_pProfile->m_wsProfileName,
1323 i_wsProfileName,
1324 KMS_MAX_ENTITY_ID);
1325 io_pProfile->m_wsProfileName[KMS_MAX_ENTITY_ID] = 0;
1326
1327 io_pProfile->m_iPortForCAService =
1328 DEFAULT_CA_SERVICE_PORT_NUMBER;
1329 io_pProfile->m_iPortForCertificateService =
1330 DEFAULT_CERTIFICATE_SERVICE_PORT_NUMBER;
1331 io_pProfile->m_iPortForDiscoveryService =
1332 DEFAULT_DISCOVERY_SERVICE_PORT_NUMBER;
1333 io_pProfile->m_iPortForAgentService =
1334 DEFAULT_AGENT_SERVICE_PORT_NUMBER;
1335 strncpy(io_pProfile->m_wsApplianceAddress,
1336 i_wsApplianceAddress,
1337 KMS_MAX_NETWORK_ADDRESS);
1338 io_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
1339 io_pProfile->m_iClusterDiscoveryFrequency = i_iClusterDiscoveryFrequency;
1340 io_pProfile->m_iTransactionTimeout = i_iTransactionTimeout;
1341 io_pProfile->m_iFailoverLimit = i_iFailOverLimit;
1342 io_pProfile->m_eKMSmode = i_eKMSmode;
1343
1344 // if the file isn't found, create a new one
1345 bool bProfileExists = ProfileExists( g_wsWorkingDirectory, /* pass in default */
1346 io_pProfile->m_wsProfileName );
1347
1348 #ifdef KMSUSERPKCS12
1349 /*
1350 * Fix logic for determining if this request is for enrollment.
1351 * Look to see if the server cert and clientkey.p12 file exist.
1352 * We always expect a password for Solaris which is used to
1353 * validate that the user has access to the clientkey data by
1354 * attempting to use it to open the PKCS12 file.
1355 */
1356 bool bEnrolling = !ClientKeyP12Exists(io_pProfile->m_wsProfileName);
1357 #else
1358 bool bEnrolling = i_wsEntityID && i_wsPassphrase;
1359 #endif
1360
1361 if ( bSuccess && !bEnrolling && !bProfileExists )
1362 {
1363 // when not enrolling a profile must exist
1364 bSuccess = false;
1365 Log(AUDIT_CLIENT_LOAD_PROFILE,
1366 i_wsProfileName,
1367 NULL,
1368 "Enrollment attempted but profile could not be found" );
1369 }
1370
1371 // if the file isn't found, create a new one
1372 if ( bSuccess && !bProfileExists )
1373 {
1374 strncpy(io_pProfile->m_wsEntityID,
1375 i_wsEntityID,
1376 KMS_MAX_ENTITY_ID );
1377 io_pProfile->m_wsEntityID[KMS_MAX_ENTITY_ID] = 0;
1378 bSuccess = CreateProfile( io_pProfile,
1379 g_wsWorkingDirectory,
1380 io_pProfile->m_wsProfileName );
1381 }
1382
1383 // load profile.cfg file
1384 if ( bSuccess )
1385 {
1386 bSuccess = GetConfig( io_pProfile );
1387
1388 }
1389
1390 // if profile settings changed then update the profile storage
1391 if ( bSuccess &&
1392 ( strncmp(io_pProfile->m_wsApplianceAddress,
1393 i_wsApplianceAddress, KMS_MAX_NETWORK_ADDRESS ) != 0 ||
1394 io_pProfile->m_iClusterDiscoveryFrequency != i_iClusterDiscoveryFrequency ||
1395 io_pProfile->m_iTransactionTimeout != i_iTransactionTimeout ||
1396 io_pProfile->m_iFailoverLimit != i_iFailOverLimit
1397 ))
1398 {
1399 strncpy(io_pProfile->m_wsApplianceAddress,
1400 i_wsApplianceAddress,
1401 KMS_MAX_NETWORK_ADDRESS);
1402 io_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
1403 io_pProfile->m_iClusterDiscoveryFrequency = i_iClusterDiscoveryFrequency;
1404 io_pProfile->m_iTransactionTimeout = i_iTransactionTimeout;
1405 io_pProfile->m_iFailoverLimit = i_iFailOverLimit;
1406
1407 bSuccess = StoreConfig( io_pProfile );
1408 }
1409
1410 // get PKI info from prior enrollment
1411 if ( bSuccess && !bEnrolling )
1412 {
1413 #ifdef KMSUSERPKCS12
1414 /*
1415 * Decrypt the PKCS12 file with the client cert and key using
1416 * the given password. If it fails, then return an auth failure
1417 * status. If success, write the client cert and key to the client file
1418 * so it can be used later by the SOAP SSL functions.
1419 */
1420 CCertificate* pEntityCertificate = new CCertificate;;
1421 CPrivateKey* pEntityPrivateKey = new CPrivateKey;
1422 bSuccess = GetPKCS12CertAndKey(io_pProfile,
1423 i_wsPassphrase,
1424 pEntityCertificate,
1425 pEntityPrivateKey);
1426 if (!bSuccess) {
1427 Log(AUDIT_CLIENT_LOAD_PROFILE,
1428 i_wsProfileName,
1429 NULL,
1430 "Enrollment Certificate and Private Key "\
1431 "were not loaded from PKCS12" );
1432 } else {
1433 /*
1434 * Write out the cert and key individually so GetPKIcerts
1435 * can use them.
1436 */
1437 bSuccess = StoreTempAgentPKI(io_pProfile,
1438 pEntityCertificate, pEntityPrivateKey);
1439 if (!bSuccess) {
1440 Log(AUDIT_CLIENT_LOAD_PROFILE,
1441 i_wsProfileName,
1442 NULL,
1443 "Enrollment Certificate and Private Key "\
1444 "were not stored to file." );
1445 }
1446 }
1447 delete pEntityCertificate;
1448 delete pEntityPrivateKey;
1449
1450 #endif
1451 if (bSuccess)
1452 bSuccess = GetPKIcerts( io_pProfile );
1453 }
1454
1455 // if not enrolling then previously enrolled PKI info should now be initialized
1456 if ( bSuccess && !bEnrolling &&
1457 (!io_pProfile->m_sHexHashedPassphrase ||
1458 !io_pProfile->m_iEnrolled ))
1459 {
1460 bSuccess = false;
1461 Log(AUDIT_CLIENT_LOAD_PROFILE,
1462 i_wsProfileName,
1463 NULL,
1464 "Enrollment Certificates and Private Key were not loaded from profile" );
1465 }
1466
1467 io_pProfile->m_bIsClusterDiscoveryCalled = false;
1468
1469 // allocate main soap struct
1470 struct soap* pstSoap = 0;
1471
1472 if ( bSuccess )
1473 {
1474 pstSoap = (struct soap*)malloc( sizeof(struct soap) );
1475
1476 io_pProfile->m_pvSoap = pstSoap;
1477
1478 bSuccess = ( pstSoap != NULL );
1479
1480 if ( bSuccess )
1481 {
1482 soap_init2( pstSoap,
1483 (SOAP_XML_STRICT | SOAP_C_UTFSTRING ),
1484 (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
1485
1486 #ifdef METAWARE
1487 K_SetupCallbacks ( pstSoap );
1488 #endif
1489
1490 soap_set_namespaces( pstSoap, KMS_Agent_namespaces );
1491
1492 pstSoap->connect_timeout = io_pProfile->m_iTransactionTimeout;
1493 pstSoap->send_timeout = io_pProfile->m_iTransactionTimeout;
1494 pstSoap->recv_timeout = io_pProfile->m_iTransactionTimeout;
1495 }
1496 else
1497 {
1498 #if defined(DEBUG) && defined(METAWARE)
1499 log_printf("Malloc %x pstSoap returned null\n",
1500 sizeof(struct soap));
1501 #endif
1502
1503 }
1504 }
1505
1506 // delete the existing cluster config if the input IP address
1507 // does not match one already known to the cluster config
1508
1509 // Note that KMSClientProfile may be too large to fit on the stack, so we're
1510 // going to put it on the heap.
1511
1512 KMSClientProfile* pstTempProfile = 0;
1513 bool bFound = false;
1514 int i;
1515
1516 if ( bSuccess )
1517 {
1518 pstTempProfile = (KMSClientProfile*)malloc( sizeof(KMSClientProfile) );
1519 bSuccess = (pstTempProfile != 0);
1520 #if defined(METAWARE)
1521 if (!bSuccess)
1522 log_printf("Malloc %x pstTempProfile returned null\n",
1523 sizeof(KMSClientProfile));
1524 #endif
1525
1526 }
1527
1528 int bClusterInformationFound = false;
1529
1530 if ( bSuccess )
1531 {
1532 memcpy( pstTempProfile, io_pProfile, sizeof(KMSClientProfile) );
1533
1534 bSuccess = LoadClusterInformation( pstTempProfile, bClusterInformationFound );
1535 }
1536
1537 // got cluster info from persistent storage
1538 if ( bSuccess && bClusterInformationFound )
1539 {
1540 // see if address is a member of the remembered cluster or is a
1541 // new kma, meaning this KMA joins the cluster as the
1542 // discovery KMA.
1543 for ( i = 0; i < pstTempProfile->m_iClusterNum; i++ )
1544 {
1545 bFound = (strncmp( pstTempProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
1546 io_pProfile->m_wsApplianceAddress,
1547 KMS_MAX_NETWORK_ADDRESS) == 0);
1548
1549 if ( bFound )
1550 {
1551 break;
1552 }
1553 #if defined(DEBUG) && defined(METAWARE)
1554 else
1555 log_printf ("KMSClient_LoadProfile : Appliance Address doesn't match");
1556 #endif
1557 }
1558
1559 if ( !bFound )
1560 {
1561 #if defined(DEBUG) && defined(METAWARE)
1562 log_printf ("KMSClient_LoadProfile : delete cluster");
1563 #endif
1564 DeleteCluster( pstTempProfile );
1565 char msg[256];
1566 K_snprintf(msg, 256,
1567 "KMSClientProfile.LoadProfile(): deleting previous cluster config, %s not found\n",
1568 io_pProfile->m_wsApplianceAddress);
1569 Log(AUDIT_CLIENT_LOAD_PROFILE,
1570 i_wsProfileName,
1571 NULL,
1572 msg );
1573 DeleteCluster( pstTempProfile );
1574 }
1575 else
1576 {
1577 // since address is a member of the persisted cluster copy the persisted cluster info to the profile
1578 io_pProfile->m_iClusterNum = pstTempProfile->m_iClusterNum;
1579 memcpy(io_pProfile->m_aCluster,
1580 pstTempProfile->m_aCluster,
1581 sizeof(KMSClusterEntry)*io_pProfile->m_iClusterNum);
1582 }
1583 }
1584 #if defined(DEBUG) && defined(METAWARE)
1585 else
1586 log_printf ("KMSClient_LoadProfile : no persisted cluster information");
1587 #endif
1588
1589 if ( pstTempProfile )
1590 {
1591 #if defined(DEBUG) && defined(METAWARE)
1592 log_printf ("KMSClient_LoadProfile : free the temporary profile");
1593 #endif
1594 free( pstTempProfile );
1595 pstTempProfile = 0;
1596 }
1597
1598 if ( bSuccess && !io_pProfile->m_iEnrolled )
1599 {
1600 #if defined(DEBUG) && defined(METAWARE)
1601 log_printf ("KMSClient_LoadProfile : call EnrollAgent");
1602 #endif
1603 // enroll the agent
1604 bSuccess = EnrollAgent( io_pProfile,
1605 i_wsEntityID,
1606 i_wsPassphrase );
1607 }
1608 #if defined(DEBUG) && defined(METAWARE)
1609 else if (io_pProfile->m_iEnrolled)
1610 log_printf ("KMSClient_LoadProfile : Already Enrolled");
1611 #endif
1612
1613
1614
1615 if (bSuccess)
1616 {
1617 // Initialize SSL - use CLIENT AUTH
1618 // CLIENT_AUTHENTICATION needs the pstSoap, and expects
1619 // the profile io_pProfile to be full (have the other certificates
1620 // and keypair)
1621
1622 if ( bSuccess )
1623 {
1624 bSuccess =
1625 K_soap_ssl_client_context(
1626 io_pProfile, // in/out
1627 pstSoap, // out
1628 SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION // in - flags
1629 ) == SOAP_OK;
1630
1631 if ( !bSuccess )
1632 {
1633 #if defined(DEBUG) && defined(METAWARE)
1634 if (!bSuccess)
1635 log_printf ("KMSClient_LoadProfile : K_soap_ssl_client_context failed");
1636 #endif
1637 GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
1638 GetPeerNetworkAddress(sKmaAddress, pstSoap);
1639
1640 LogError(io_pProfile,
1641 AUDIT_CLIENT_LOAD_PROFILE_SOAP_ERROR,
1642 NULL,
1643 sKmaAddress,
1644 sSoapFaultMsg );
1645 }
1646 }
1647
1648 // discover the cluster
1649
1650 if ( bSuccess &&
1651 io_pProfile->m_iClusterDiscoveryFrequency > 0 )
1652 {
1653 bSuccess = ( KMSClient_GetClusterInformation(
1654 io_pProfile,
1655 io_pProfile->m_wsEntitySiteID,
1656 sizeof(io_pProfile->m_wsEntitySiteID),
1657 &(io_pProfile->m_iClusterNum),
1658 io_pProfile->m_aCluster,
1659 KMS_MAX_CLUSTER_NUM) != 0 );
1660 // KMSClient_GetClusterInformation logs errors
1661
1662 if (bSuccess && i_eKMSmode == FIPS_MODE)
1663 {
1664 bSuccess = !KMSClient_NoFIPSCompatibleKMAs(io_pProfile);
1665 if (!bSuccess)
1666 {
1667 LogError(io_pProfile,
1668 AUDIT_CLIENT_AGENT_LOAD_PROFILE_NO_FIPS_COMPATIBLE_KMAS_AVAILABLE,
1669 NULL,
1670 NULL,
1671 NULL );
1672 }
1673 }
1674 }
1675 #if defined(DEBUG) && defined(METAWARE)
1676 if (!bSuccess)
1677 log_printf ("KMSClient_LoadProfile : getClusterInformation failed");
1678 #endif
1679
1680 #ifdef KMSUSERPKCS12
1681 /*
1682 * Once the SSL context is established, delete the
1683 * private key file.
1684 */
1685 (void) CleanupPrivateKeyFile(io_pProfile);
1686 #endif
1687 }
1688 #if defined(DEBUG) && defined(METAWARE)
1689 else if (!bSuccess)
1690 log_printf ("KMSClient_LoadProfile : EnrollAgent failed");
1691 #endif
1692
1693 CAgentLoadBalancer *pAgentLoadBalancer = new CAgentLoadBalancer(io_pProfile);
1694 if(pAgentLoadBalancer == NULL)
1695 {
1696 bSuccess = false;
1697 }
1698
1699 #if defined(DEBUG) && defined(METAWARE)
1700 if (!bSuccess)
1701 log_printf ("KMSClient_LoadProfile : new CAgentLoadBalancer failed");
1702 #endif
1703
1704 io_pProfile->m_pAgentLoadBalancer = pAgentLoadBalancer;
1705
1706 // create a data unit server affinity cache for Agents
1707
1708 if ( bSuccess )
1709 {
1710 io_pProfile->m_pDataUnitCache = new CDataUnitCache();
1711
1712 bSuccess = ( io_pProfile->m_pDataUnitCache != NULL );
1713 }
1714
1715 if ( bSuccess )
1716 {
1717 #if defined(DEBUG) && defined(METAWARE)
1718 log_printf ("KMSClient_LoadProfile : set version to KMS_AGENT_VERSION = %x",
1719 KMS_AGENT_VERSION);
1720 log_printf ("KMSClient_LoadProfile : profile is: %x\n", io_pProfile);
1721 #endif
1722 // this is checked later by ProfileLoaded and is taken
1723 // to indicate that the profile was correctly loaded
1724 io_pProfile->m_iVersion = KMS_AGENT_VERSION;
1725 }
1726
1727 if( !bSuccess )
1728 {
1729 K_DestroyMutex((K_MUTEX_HANDLE)io_pProfile->m_pLock);
1730 io_pProfile->m_pLock = 0;
1731
1732 if ( io_pProfile->m_pvSoap )
1733 {
1734 soap_destroy( (struct soap*)io_pProfile->m_pvSoap );
1735 soap_end( (struct soap*)io_pProfile->m_pvSoap );
1736 soap_done( (struct soap*)io_pProfile->m_pvSoap );
1737
1738 free( (struct soap*)io_pProfile->m_pvSoap );
1739 io_pProfile->m_pvSoap = 0;
1740
1741 if( io_pProfile->m_pAgentLoadBalancer != NULL)
1742 {
1743 delete(reinterpret_cast <CAgentLoadBalancer *>(io_pProfile->m_pAgentLoadBalancer));
1744 }
1745
1746 if( io_pProfile->m_pDataUnitCache != NULL)
1747 {
1748 delete(reinterpret_cast <CDataUnitCache *>(io_pProfile->m_pDataUnitCache));
1749 }
1750
1751 }
1752 #if defined(DEBUG) && defined(METAWARE)
1753 log_printf ("KMSClient_LoadProfile : failed - returning");
1754 #endif
1755 }
1756
1757 return bSuccess;
1758 }
1759
1760 /**
1761 * compare cluster entries having equivalent KMA names (aka Appliance alias) and
1762 * return true if equal. Note: KMANetworkAddress comparison is handled separately
1763 * due to IPv4/IPv6
1764 */
EqualClusterEntry(struct KMS_Discovery::KMS_Discovery_ClusterMember const * i_pLeft,KMSClusterEntry const * i_pRight)1765 static bool EqualClusterEntry(
1766 struct KMS_Discovery::KMS_Discovery_ClusterMember const *i_pLeft,
1767 KMSClusterEntry const *i_pRight)
1768 {
1769 bool bEnabled = i_pRight->m_iEnabled ? true : false;
1770 if ( i_pLeft->Enabled != bEnabled )
1771 {
1772 return false;
1773 }
1774 if ( i_pLeft->KMAID != i_pRight->m_lApplianceID )
1775 {
1776 return false;
1777 }
1778 if ( strncmp(i_pLeft->KMASiteID,
1779 i_pRight->m_wsApplianceSiteID,
1780 KMS_MAX_ENTITY_SITE_ID) != 0 )
1781 {
1782 return false;
1783 }
1784 // Note: we now minimize persistence of cluster changes by not saving
1785 // whenever m_iResponding changes
1786
1787 return true;
1788 }
1789 /**
1790 * @return true if the current address matches the provided IPv6Address
1791 * when the i_bUseIPv6 arg is true, otherwise compare the current address
1792 * with the IPv4Address. If i_bUseIPv6 then i_pCurrentAddress must be
1793 * enclosed in brackets, i.e. as in RFC 2396.
1794 */
EqualKMANetworkAddress(bool i_bUseIPv6,const char * const i_pIPv6Address,const char * const i_pIPv4Address,const char * const i_pCurrentAddress)1795 static bool EqualKMANetworkAddress (
1796 bool i_bUseIPv6,
1797 const char * const i_pIPv6Address,
1798 const char * const i_pIPv4Address,
1799 const char * const i_pCurrentAddress
1800 )
1801 {
1802 bool bEqualAddress = true;
1803
1804 if ( i_pCurrentAddress == NULL )
1805 {
1806 return false;
1807 }
1808
1809 if (i_bUseIPv6)
1810 {
1811 if ( i_pIPv6Address == NULL )
1812 {
1813 return false;
1814 }
1815 char sIPv6Address[KMS_MAX_NETWORK_ADDRESS] = "[";
1816
1817 strcat(sIPv6Address, i_pIPv6Address);
1818
1819 char * pLoc = strchr(sIPv6Address, '/');
1820
1821 if ( pLoc != NULL )
1822 {
1823 // remove prefix from address
1824 *pLoc = '\0';
1825 }
1826 strcat(sIPv6Address, "]");
1827 bEqualAddress = strncmp(sIPv6Address, i_pCurrentAddress, KMS_MAX_NETWORK_ADDRESS) == 0;
1828 }
1829 else
1830 {
1831 if ( i_pIPv4Address == NULL )
1832 {
1833 return false;
1834 }
1835 bEqualAddress = strncmp(i_pIPv4Address, i_pCurrentAddress, KMS_MAX_NETWORK_ADDRESS) == 0;
1836 }
1837
1838 return bEqualAddress;
1839 }
1840
1841 /**
1842 * compares the profile's current cluster state with the filtered discover
1843 * cluster response and returns true if the repsonse
1844 * differs from i_pProfile->m_aCluster. A cluster has changed if the state of any
1845 * cluster node has changed or if the set of cluster nodes has changed.
1846 * The order of nodes is immaterial.
1847 */
ClusterConfigChanged(KMSClientProfile const * i_pProfile,char * const i_sResponseEntitySiteID,struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers const * i_pFilteredCluster)1848 static bool ClusterConfigChanged (
1849 KMSClientProfile const *i_pProfile,
1850 char * const i_sResponseEntitySiteID,
1851 struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers const *i_pFilteredCluster)
1852 {
1853 int i, j;
1854
1855 FATAL_ASSERT(i_pProfile);
1856 FATAL_ASSERT(i_pFilteredCluster);
1857
1858 // cardinality check
1859 if (i_pProfile->m_iClusterNum !=
1860 i_pFilteredCluster->__size)
1861 {
1862 return true;
1863 }
1864
1865 // check if the agent's site ID changed
1866 if (strncmp(i_pProfile->m_wsEntitySiteID,
1867 i_sResponseEntitySiteID, KMS_MAX_ENTITY_SITE_ID) != 0)
1868 {
1869 return true;
1870 }
1871
1872 // for all KMAs in filtered response check if they exist unchanged in the profile
1873 for (i = 0; i < i_pFilteredCluster->__size; i++)
1874 {
1875 bool bFound = false;
1876 for (j = 0; j < i_pProfile->m_iClusterNum; j++)
1877 {
1878 if (strncmp(i_pFilteredCluster->__ptr[i].KMAName,
1879 i_pProfile->m_aCluster[j].m_wsApplianceAlias,
1880 KMS_MAX_ENTITY_ID) == 0)
1881 {
1882 bFound = true;
1883 if (
1884 !EqualKMANetworkAddress(
1885 strchr(i_pProfile->m_wsApplianceAddress, ':') ? true : false,
1886 i_pFilteredCluster->__ptr[i].KMANetworkAddressIPv6,
1887 i_pFilteredCluster->__ptr[i].KMANetworkAddress,
1888 i_pProfile->m_aCluster[j].m_wsApplianceNetworkAddress) ||
1889 !EqualClusterEntry((i_pFilteredCluster->__ptr + i),
1890 &i_pProfile->m_aCluster[j]))
1891
1892 {
1893 return true;
1894 }
1895 }
1896 }
1897 if ( !bFound )
1898 {
1899 return true;
1900 }
1901 }
1902 return false;
1903 }
1904
1905 /**
1906 * returns true if the string is a valid IPv6 address syntactically
1907 */
ValidIPv6KMAaddress(const char * const i_pIPAddress)1908 static bool ValidIPv6KMAaddress( const char * const i_pIPAddress )
1909 {
1910 FATAL_ASSERT( i_pIPAddress );
1911
1912 if ( strlen(i_pIPAddress) <= 0 )
1913 {
1914 return false;
1915 }
1916
1917 // simple check
1918 if ( strchr( i_pIPAddress, ':'))
1919 {
1920 return true;
1921 }
1922
1923 return false;
1924 }
1925 /**
1926 *
1927 */
FreeFilteredCluster(struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster,int iLimit)1928 static void FreeFilteredCluster (
1929 struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster,
1930 int iLimit )
1931 {
1932 int j = 0;
1933 for (; j < iLimit; j++ )
1934 {
1935 free( io_stFilteredCluster->__ptr[j].KMAName );
1936 free( io_stFilteredCluster->__ptr[j].KMASiteID );
1937 free( io_stFilteredCluster->__ptr[j].KMAHostName );
1938 free( io_stFilteredCluster->__ptr[j].KMANetworkAddress );
1939 free( io_stFilteredCluster->__ptr[j].KMAVersion );
1940 free( io_stFilteredCluster->__ptr[j].KMAHostNameIPv6 );
1941 free( io_stFilteredCluster->__ptr[j].KMANetworkAddressIPv6 );
1942 }
1943
1944 free( io_stFilteredCluster->__ptr );
1945 }
1946
1947 /**
1948 * filters the discover cluster response to be less than or equal to KMS_MAX_CLUSTER_NUM KMAs. The heuristic used to filter
1949 * the response is the same as used by CAgentLoadBalancer::KMSClient_SortClusterArray(), FIPS compatibility, then within site,
1950 * then responding and enabled KMAs.
1951 * @param i_stResponse pointer to gsoap discover cluster service response
1952 * @param io_stFilteredCluster pointer to gsoap discover cluster array to be populated with the filtered list of KMAs
1953 * @return true on success and io_stFilteredCluster->__size less than or equal to KMS_MAX_CLUSTER_NUM,
1954 * otherwise io_stFilteredCluster is undefined. io_stFilteredCluster->__ptr is populated with the array of elements
1955 * malloc'd.
1956 */
FilterCluster(struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse * const i_stResponse,bool i_bFIPS,struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster)1957 static bool FilterCluster (struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse * const i_stResponse,
1958 bool i_bFIPS,
1959 struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster)
1960 {
1961 /*
1962 * do something like KMSAgentLoadBalancer:SortClusterArray() to the stResponse array
1963 * return 1st KMS_MAX_CLUSTER_NUM entries and free the rest.
1964 */
1965
1966 FATAL_ASSERT(i_stResponse);
1967 FATAL_ASSERT(io_stFilteredCluster);
1968
1969 io_stFilteredCluster->__size = i_stResponse->ArrayOfClusterMembers.__size;
1970 io_stFilteredCluster->__ptr = reinterpret_cast < struct KMS_Discovery::KMS_Discovery_ClusterMember * >
1971 ( calloc( io_stFilteredCluster->__size,
1972 sizeof (struct KMS_Discovery::KMS_Discovery_ClusterMember ) ) );
1973
1974 if (io_stFilteredCluster->__ptr == NULL)
1975 {
1976 Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
1977 NULL,
1978 NULL,
1979 "calloc failed");
1980 return false;
1981 }
1982
1983 if (io_stFilteredCluster->__size <= 0)
1984 {
1985 Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
1986 NULL,
1987 NULL,
1988 "returned cluster size is not positive");
1989 return false;
1990 }
1991
1992 // copy response cluster members
1993 for (int i = 0; i < io_stFilteredCluster->__size; i++)
1994 {
1995 bool bSuccess = true;
1996
1997 size_t iKMANameSize = 0, iKMASiteIDSize = 0, iKMAHostNameSize = 0,
1998 iKMANetworkAddressSize = 0, iKMAVersionSize = 0, iKMAHostNameIPv6Size = 0,
1999 iKMANetworkAddressIPv6Size = 0;
2000
2001 // allocate storage for the various struct member's arrays
2002 iKMANameSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAName)+1;
2003 io_stFilteredCluster->__ptr[i].KMAName = reinterpret_cast <char *> (malloc(iKMANameSize));
2004
2005 iKMASiteIDSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMASiteID)+1;
2006 io_stFilteredCluster->__ptr[i].KMASiteID = reinterpret_cast <char *> (malloc(iKMASiteIDSize));
2007
2008 iKMAHostNameSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostName)+1;
2009 io_stFilteredCluster->__ptr[i].KMAHostName = reinterpret_cast <char *> (malloc(iKMAHostNameSize));
2010
2011 iKMANetworkAddressSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddress)+1;
2012 io_stFilteredCluster->__ptr[i].KMANetworkAddress = reinterpret_cast <char *> (malloc(iKMANetworkAddressSize));
2013
2014 // KMAVersion is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2015 if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion)
2016 {
2017 iKMAVersionSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion)+1;
2018 io_stFilteredCluster->__ptr[i].KMAVersion = reinterpret_cast <char *> (malloc(iKMAVersionSize));
2019 if (io_stFilteredCluster->__ptr[i].KMAVersion == NULL)
2020 {
2021 bSuccess = false;
2022 }
2023 }
2024 else
2025 {
2026 io_stFilteredCluster->__ptr[i].KMAVersion = NULL;
2027 }
2028
2029 // KMAHostNameIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2030 if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6)
2031 {
2032 iKMAHostNameIPv6Size = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6)+1;
2033 io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 = reinterpret_cast <char *> (malloc(iKMAHostNameIPv6Size));
2034 if ( io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 == NULL )
2035 {
2036 bSuccess = false;
2037 }
2038 }
2039 else
2040 {
2041 io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 = NULL;
2042 }
2043
2044 // KMANetworkAddressIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2045 if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6)
2046 {
2047 iKMANetworkAddressIPv6Size = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6)+1;
2048 io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 = reinterpret_cast <char *> (malloc(iKMANetworkAddressIPv6Size));
2049 if ( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 == NULL )
2050 {
2051 bSuccess = false;
2052 }
2053 }
2054 else
2055 {
2056 io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 = NULL;
2057 }
2058
2059 if ( io_stFilteredCluster->__ptr[i].KMAName == NULL ||
2060 io_stFilteredCluster->__ptr[i].KMASiteID == NULL ||
2061 io_stFilteredCluster->__ptr[i].KMAHostName == NULL ||
2062 io_stFilteredCluster->__ptr[i].KMANetworkAddress == NULL ||
2063 !bSuccess )
2064 {
2065 // cleanup and return
2066 FreeFilteredCluster( io_stFilteredCluster, i+1 );
2067 Log( AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
2068 NULL,
2069 NULL,
2070 "malloc failed" );
2071 return false;
2072 }
2073
2074 strncpy(io_stFilteredCluster->__ptr[i].KMAName,
2075 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAName,
2076 iKMANameSize);
2077 io_stFilteredCluster->__ptr[i].KMAName[iKMANameSize-1] = '\0';
2078
2079 strncpy(io_stFilteredCluster->__ptr[i].KMASiteID,
2080 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMASiteID,
2081 iKMASiteIDSize);
2082 io_stFilteredCluster->__ptr[i].KMASiteID[iKMASiteIDSize-1] = '\0';
2083
2084 strncpy(io_stFilteredCluster->__ptr[i].KMAHostName,
2085 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostName,
2086 iKMAHostNameSize);
2087 io_stFilteredCluster->__ptr[i].KMAHostName[iKMAHostNameSize-1] = '\0';
2088
2089 strncpy(io_stFilteredCluster->__ptr[i].KMANetworkAddress,
2090 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddress,
2091 iKMANetworkAddressSize);
2092 io_stFilteredCluster->__ptr[i].KMANetworkAddress[iKMANetworkAddressSize-1] = '\0';
2093
2094 if ( io_stFilteredCluster->__ptr[i].KMAVersion )
2095 {
2096 strncpy( io_stFilteredCluster->__ptr[i].KMAVersion,
2097 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion,
2098 iKMAVersionSize );
2099 io_stFilteredCluster->__ptr[i].KMAVersion[iKMAVersionSize-1] = '\0';
2100 }
2101
2102 if (io_stFilteredCluster->__ptr[i].KMAHostNameIPv6)
2103 {
2104 strncpy(io_stFilteredCluster->__ptr[i].KMAHostNameIPv6,
2105 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6,
2106 iKMAHostNameIPv6Size);
2107 io_stFilteredCluster->__ptr[i].KMAHostNameIPv6[iKMAHostNameIPv6Size-1] = '\0';
2108 }
2109
2110 if ( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 )
2111 {
2112 strncpy( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6,
2113 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6,
2114 iKMANetworkAddressIPv6Size );
2115 io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6[iKMANetworkAddressIPv6Size-1] = '\0';
2116 }
2117
2118 io_stFilteredCluster->__ptr[i].KMAID = i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAID;
2119 io_stFilteredCluster->__ptr[i].Enabled = i_stResponse->ArrayOfClusterMembers.__ptr[i].Enabled;
2120 io_stFilteredCluster->__ptr[i].KMS_Discovery__Locked = i_stResponse->ArrayOfClusterMembers.__ptr[i].KMS_Discovery__Locked;
2121
2122 // set load to zero, KMA with version <= Build600 don't initialize
2123 // the load field from the service network
2124 if ( ( io_stFilteredCluster->__ptr[i].KMAVersion &&
2125 strcmp( io_stFilteredCluster->__ptr[i].KMAVersion, "Build600" ) <= 0 ) ||
2126 io_stFilteredCluster->__ptr[i].KMAVersion == NULL )
2127 {
2128 io_stFilteredCluster->__ptr[i].Load = 0;
2129 }
2130 else
2131 {
2132 io_stFilteredCluster->__ptr[i].Load = i_stResponse->ArrayOfClusterMembers.__ptr[i].Load;
2133 }
2134
2135 io_stFilteredCluster->__ptr[i].Responding = i_stResponse->ArrayOfClusterMembers.__ptr[i].Responding;
2136
2137 if (!bSuccess)
2138 {
2139 FreeFilteredCluster( io_stFilteredCluster, i );
2140 Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
2141 NULL,
2142 NULL,
2143 "cluster member copy failed");
2144 return false;
2145 }
2146 }
2147
2148 // is filtering necessary?
2149 if (io_stFilteredCluster->__size <= KMS_MAX_CLUSTER_NUM)
2150 {
2151 // no filtering required
2152 return true;
2153 }
2154 else
2155 {
2156 char sMesg[100];
2157 K_snprintf(sMesg, sizeof (sMesg), "DiscoverCluster returned %d KMAs, filtering to %d ...", io_stFilteredCluster->__size, KMS_MAX_CLUSTER_NUM);
2158 Log(AUDIT_CLIENT_FILTER_CLUSTER,
2159 NULL,
2160 NULL,
2161 sMesg);
2162
2163 }
2164
2165 // adjust loads according to availability, site and FIPS compatibility
2166 {
2167 int i = 0;
2168 for (; i < io_stFilteredCluster->__size; i++)
2169 {
2170 if (io_stFilteredCluster->__ptr[i].Enabled == false
2171 || io_stFilteredCluster->__ptr[i].Responding == false
2172 || io_stFilteredCluster->__ptr[i].KMS_Discovery__Locked == true)
2173 {
2174 io_stFilteredCluster->__ptr[i].Load += 0x40;
2175 }
2176
2177 if (strcmp(io_stFilteredCluster->__ptr[i].KMASiteID,
2178 i_stResponse->EntitySiteID) != 0)
2179 {
2180 io_stFilteredCluster->__ptr[i].Load += 0x20;
2181
2182 }
2183
2184 if ( i_bFIPS &&
2185 !FIPScompatibleKMA(io_stFilteredCluster->__ptr[i].KMAVersion))
2186 {
2187 io_stFilteredCluster->__ptr[i].Load += 0x80;
2188 }
2189 }
2190 }
2191
2192 // sort ascending by load
2193
2194 // gnome sort: the simplest sort algoritm
2195 {
2196 int i = 0;
2197 while (i < io_stFilteredCluster->__size)
2198 {
2199 if (i == 0 || io_stFilteredCluster->__ptr[i - 1].Load <= io_stFilteredCluster->__ptr[i].Load)
2200 {
2201 i++;
2202 }
2203 else
2204 {
2205 struct KMS_Discovery::KMS_Discovery_ClusterMember tmp = io_stFilteredCluster->__ptr[i];
2206 io_stFilteredCluster->__ptr[i] = io_stFilteredCluster->__ptr[i - 1];
2207 io_stFilteredCluster->__ptr[--i] = tmp;
2208 }
2209 }
2210 }
2211
2212 // now filter the list, freeing memory allocated for copied elements that are not being retained
2213 {
2214 int i=KMS_MAX_CLUSTER_NUM;
2215 for (; i < io_stFilteredCluster->__size; i++)
2216 {
2217 free(io_stFilteredCluster->__ptr[i].KMAName);
2218 free(io_stFilteredCluster->__ptr[i].KMASiteID);
2219 free(io_stFilteredCluster->__ptr[i].KMAHostName);
2220 free(io_stFilteredCluster->__ptr[i].KMANetworkAddress);
2221 free(io_stFilteredCluster->__ptr[i].KMAVersion);
2222 free(io_stFilteredCluster->__ptr[i].KMAHostNameIPv6);
2223 free(io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6);
2224 }
2225 }
2226
2227 io_stFilteredCluster->__size = KMS_MAX_CLUSTER_NUM;
2228
2229 Log(AUDIT_CLIENT_FILTER_CLUSTER,
2230 NULL,
2231 NULL,
2232 "success");
2233
2234 return true;
2235 };
2236
2237 /*---------------------------------------------------------------------------
2238 * Function: KMSClient_GetClusterInformation
2239 *
2240 *--------------------------------------------------------------------------*/
KMSClient_GetClusterInformation(KMSClientProfile * i_pProfile,utf8char * o_wsEntitySiteID,int i_iEntitySiteIDSize,int * o_pApplianceNum,KMSClusterEntry * o_pClusterEntryArray,int i_iClusterEntryArraySize)2241 bool KMSClient_GetClusterInformation(
2242 KMSClientProfile *i_pProfile,
2243 utf8char *o_wsEntitySiteID,
2244 int i_iEntitySiteIDSize,
2245 int *o_pApplianceNum,
2246 KMSClusterEntry *o_pClusterEntryArray,
2247 int i_iClusterEntryArraySize)
2248 {
2249 FATAL_ASSERT(i_pProfile);
2250 FATAL_ASSERT( o_wsEntitySiteID );
2251 FATAL_ASSERT( o_pApplianceNum );
2252 FATAL_ASSERT( o_pClusterEntryArray );
2253 FATAL_ASSERT( i_iEntitySiteIDSize <= KMS_MAX_ENTITY_ID+1 );
2254
2255 CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
2256
2257 bool bSuccess = true;
2258 char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
2259 char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
2260
2261 char sURL[KMS_MAX_URL+1];
2262
2263 // set URL from the initial appliance address
2264 utf8cstr sApplianceAddress = i_pProfile->m_wsApplianceAddress;
2265
2266 #if defined(DEBUG) && defined(METAWARE)
2267 log_printf("KMSClient_GetClusterInformation : entered");
2268 #endif
2269
2270 K_snprintf(sURL,
2271 KMS_MAX_URL,
2272 "https://%s:%d",
2273 sApplianceAddress,
2274 i_pProfile->m_iPortForDiscoveryService);
2275 strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
2276 i_pProfile->m_sURL[KMS_MAX_URL] = 0;
2277
2278 // allocate and initialize a new soap env for the cluster discovery call
2279 struct soap *pstSoap = (struct soap*)i_pProfile->m_pvDiscoverySoap;
2280
2281 if ( !i_pProfile->m_iEnrolled )
2282 {
2283 bSuccess = false;
2284 }
2285
2286 if ( bSuccess )
2287 {
2288 // allocate discovery soap runtime
2289 if (pstSoap == NULL )
2290 {
2291 pstSoap = soap_new();
2292 i_pProfile->m_pvDiscoverySoap = pstSoap;
2293 /* soap_copy results in a segfault in sk_free() within libcrytpo.so
2294 pstSoap = soap_copy( (soap*)i_pProfile->m_pvSoap );
2295 */
2296 if (pstSoap == NULL)
2297 {
2298 bSuccess = false;
2299 }
2300 else
2301 {
2302 pstSoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
2303 pstSoap->send_timeout = i_pProfile->m_iTransactionTimeout;
2304 pstSoap->recv_timeout = i_pProfile->m_iTransactionTimeout;
2305
2306 soap_set_imode( pstSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
2307 soap_set_omode( pstSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
2308
2309 soap_set_namespaces( pstSoap, KMS_Discovery_namespaces );
2310 bSuccess = K_soap_ssl_client_context(
2311 i_pProfile,
2312 pstSoap,
2313 SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION
2314 ) == SOAP_OK;
2315 if ( !bSuccess )
2316 {
2317 Log(AUDIT_CLIENT_GetClusterInformation,
2318 NULL,
2319 NULL,
2320 "K_soap_ssl_client_context failed");
2321 soap_destroy(pstSoap);
2322 soap_end(pstSoap);
2323 soap_done(pstSoap);
2324 }
2325 }
2326 }
2327 }
2328
2329 // Discovery
2330 struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse stResponse;
2331
2332 #if defined(DEBUG) && defined(METAWARE)
2333 log_printf("KMSClient_GetClusterInformation : call KMS_Discovery_DiscoverCluster");
2334 #endif
2335
2336 // SOAP - discover cluster
2337 if ( bSuccess )
2338 {
2339 #ifdef DEBUG
2340 int iStartTickCount = K_GetTickCount();
2341 int iEndTickCount;
2342 char sDiscoverTimeMsg[100];
2343 #endif
2344 bSuccess =
2345 KMS_Discovery::soap_call_KMS_Discovery__DiscoverCluster(
2346 pstSoap,
2347 sURL,
2348 NULL,
2349 NULL,
2350 stResponse ) == SOAP_OK;
2351 #ifdef DEBUG
2352 iEndTickCount = K_GetTickCount();
2353 sprintf(sDiscoverTimeMsg, "DiscoverCluster soapcall elapsed time=%u ms",
2354 iEndTickCount-iStartTickCount);
2355 Log(AUDIT_CLIENT_GetClusterInformation,
2356 NULL,
2357 sApplianceAddress,
2358 sDiscoverTimeMsg);
2359 #endif
2360
2361 if ( !bSuccess )
2362 {
2363 GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
2364 GetPeerNetworkAddress(sKmaAddress, pstSoap);
2365 LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION_SOAP_ERROR,
2366 NULL,
2367 sKmaAddress,
2368 sSoapFaultMsg );
2369
2370 if ( !ServerError( sSoapFaultMsg, pstSoap->errnum ) )
2371 {
2372 // do not failover if error is client related
2373 soap_destroy( pstSoap );
2374 soap_end( pstSoap );
2375 soap_free( pstSoap );
2376 return false;
2377 }
2378 }
2379
2380 // If we did not succeed to Discover from the initial appliance,
2381 // try to discover from other appliances that we know about that are enabled.
2382 // Disabled Appliances are not attempted because they may have a stale view
2383 // of the cluster. In particular, they themselves are not aware that they
2384 // are disabled.
2385
2386 if ( !bSuccess && i_pProfile->m_iClusterNum > 0 )
2387 {
2388 // Copy the profile's cluster array so that we don't have to lock the
2389 // profile around a SOAP call
2390
2391 int j = 0;
2392 int iClusterNum = 0;
2393 KMSClusterEntry* aCluster =
2394 (KMSClusterEntry*)malloc(sizeof(KMSClusterEntry) * KMS_MAX_CLUSTER_NUM);
2395
2396 bSuccess = ( aCluster != 0 );
2397 #if defined(DEBUG) && defined(METAWARE)
2398 if (!bSuccess)
2399 log_printf("Malloc %x aCluster returned null\n",
2400 sizeof(KMSClusterEntry) * KMS_MAX_CLUSTER_NUM);
2401 #endif
2402
2403 if ( bSuccess )
2404 {
2405 iClusterNum = i_pProfile->m_iClusterNum;
2406 memcpy( aCluster, i_pProfile->m_aCluster,
2407 sizeof(KMSClusterEntry) * iClusterNum );
2408
2409 // initialize to false since all KMAs could be disabled
2410 bSuccess = false;
2411 for ( j = 0; j < iClusterNum; j++ )
2412 {
2413 if ( aCluster[j].m_iEnabled == FALSE )
2414 {
2415 continue;
2416 }
2417
2418 sApplianceAddress = aCluster[j].m_wsApplianceNetworkAddress;
2419 K_snprintf(sURL,
2420 KMS_MAX_URL,
2421 "https://%s:%d",
2422 sApplianceAddress,
2423 i_pProfile->m_iPortForDiscoveryService);
2424
2425 Log(AUDIT_CLIENT_GetClusterInformation,
2426 NULL,
2427 sApplianceAddress,
2428 "Failing over and trying this appliance");
2429
2430 // SOAP - discover cluster
2431 bSuccess =
2432 KMS_Discovery::soap_call_KMS_Discovery__DiscoverCluster(
2433 pstSoap,
2434 sURL,
2435 NULL,
2436 NULL,
2437 stResponse ) == SOAP_OK;
2438
2439 if ( !bSuccess )
2440 {
2441 GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
2442 GetPeerNetworkAddress(sKmaAddress, pstSoap);
2443 LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION_SOAP_ERROR,
2444 NULL,
2445 sKmaAddress,
2446 sSoapFaultMsg );
2447 }
2448 else
2449 {
2450 // The discover succeeded
2451 break;
2452 }
2453 }
2454 }
2455
2456 if ( aCluster != 0 )
2457 {
2458 free(aCluster);
2459 }
2460
2461 if ( bSuccess )
2462 {
2463 // Set the Profile's initial appliance to the Appliance
2464 // that we just succeeded to Discover from. KMSClient_SelectAppliance()
2465 // persists the updated config
2466 KMSClient_SelectAppliance( i_pProfile,
2467 i_pProfile->m_aCluster[j].m_wsApplianceNetworkAddress );
2468 }
2469 }
2470 }
2471
2472 if ( bSuccess )
2473 {
2474 if (((int)strlen(stResponse.EntitySiteID) > i_iEntitySiteIDSize - 1))
2475 {
2476 bSuccess = false;
2477 LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION,
2478 NULL,
2479 NULL,
2480 "returned site id size too large" );
2481 }
2482 }
2483
2484 // copy returned cluster information into i_pProfile->m_aCluster after
2485 // filtering the cluster members to a list with size <= KMS_MAX_CLUSTER_NUM
2486 if ( bSuccess )
2487 {
2488 KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers aFilteredCluster;
2489
2490 bSuccess = FilterCluster(&stResponse, i_pProfile->m_eKMSmode == FIPS_MODE, &aFilteredCluster);
2491 if (!bSuccess )
2492 {
2493 LogError(i_pProfile, AUDIT_CLIENT_GET_CLUSTER_INFORMATION,
2494 NULL,
2495 NULL,
2496 "cluster response filtering failed" );
2497 }
2498
2499 if(bSuccess)
2500 {
2501 int i;
2502 bool bPersistClusterConfig = ClusterConfigChanged(i_pProfile,
2503 stResponse.EntitySiteID,
2504 &aFilteredCluster);
2505
2506 strncpy(o_wsEntitySiteID,stResponse.EntitySiteID, i_iEntitySiteIDSize-1 );
2507 o_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2508
2509 strncpy(i_pProfile->m_wsEntitySiteID, stResponse.EntitySiteID, i_iEntitySiteIDSize-1 );
2510 i_pProfile->m_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2511
2512 // fill the aCluster array in the i_pProfile
2513 i_pProfile->m_iClusterNum = aFilteredCluster.__size;
2514 for (i = 0; i < i_pProfile->m_iClusterNum; i++)
2515 {
2516 i_pProfile->m_aCluster[i].m_lApplianceID =
2517 (aFilteredCluster.__ptr+i)->KMAID;
2518 i_pProfile->m_aCluster[i].m_iEnabled =
2519 (aFilteredCluster.__ptr+i)->Enabled;
2520 i_pProfile->m_aCluster[i].m_iResponding =
2521 (aFilteredCluster.__ptr+i)->Responding;
2522
2523 i_pProfile->m_aCluster[i].m_lLoad = (aFilteredCluster.__ptr+i)->Load;
2524 strncpy(i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2525 (aFilteredCluster.__ptr+i)->KMAName,
2526 KMS_MAX_ENTITY_ID);
2527 i_pProfile->m_aCluster[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2528 // if the m_wsApplianceAddress is IPv6 then we'll store
2529 // KMA IPv6 addresses if they have one
2530 if ( strchr( i_pProfile->m_wsApplianceAddress, ':') )
2531 {
2532 // KMAs prior to 2.1, or 2.1 KMAs at rep schema < 10
2533 // will not have IPv6 attributes in the soap response
2534 if ( (aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6 &&
2535 ValidIPv6KMAaddress((aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6))
2536 {
2537 strcpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress, "[");
2538 char * pLoc = strchr((aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6,
2539 '/');
2540 if ( pLoc != NULL )
2541 {
2542 // remove prefix from address
2543 *pLoc = '\0';
2544 strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2545 (aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6 );
2546 }
2547 else
2548 {
2549 strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2550 (aFilteredCluster.__ptr + i)->KMANetworkAddressIPv6);
2551 }
2552 strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress, "]");
2553 }
2554 else
2555 {
2556 // use the IPv4 address
2557 strncpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2558 (aFilteredCluster.__ptr+i)->KMANetworkAddress,
2559 KMS_MAX_NETWORK_ADDRESS);
2560 }
2561 }
2562 else
2563 {
2564 strncpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2565 (aFilteredCluster.__ptr+i)->KMANetworkAddress,
2566 KMS_MAX_NETWORK_ADDRESS);
2567 }
2568 i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2569 strncpy(i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2570 (aFilteredCluster.__ptr+i)->KMASiteID,
2571 KMS_MAX_ENTITY_SITE_ID);
2572 i_pProfile->m_aCluster[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2573
2574 if ((aFilteredCluster.__ptr + i)->KMAVersion)
2575 {
2576 strncpy(i_pProfile->m_aCluster[i].m_sKMAVersion,
2577 (aFilteredCluster.__ptr + i)->KMAVersion,
2578 KMS_MAX_VERSION_LENGTH);
2579 i_pProfile->m_aCluster[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2580 }
2581 else
2582 {
2583 i_pProfile->m_aCluster[i].m_sKMAVersion[0] = '\0';
2584 }
2585
2586 if ((aFilteredCluster.__ptr + i)->KMS_Discovery__Locked)
2587 {
2588 i_pProfile->m_aCluster[i].m_iKMALocked = TRUE;
2589 }
2590 else
2591 {
2592 i_pProfile->m_aCluster[i].m_iKMALocked = FALSE;
2593 }
2594 }
2595
2596 // now release malloc'd storage from filtering the cluster response
2597 FreeFilteredCluster( &aFilteredCluster, aFilteredCluster.__size );
2598
2599 // fill the array specified by the caller
2600 *o_pApplianceNum = i_pProfile->m_iClusterNum;
2601 for (i = 0; i < i_pProfile->m_iClusterNum; i++)
2602 {
2603 o_pClusterEntryArray[i].m_lApplianceID = i_pProfile->m_aCluster[i].m_lApplianceID;
2604 o_pClusterEntryArray[i].m_iEnabled = i_pProfile->m_aCluster[i].m_iEnabled;
2605 o_pClusterEntryArray[i].m_iResponding = i_pProfile->m_aCluster[i].m_iResponding;
2606 o_pClusterEntryArray[i].m_lLoad = i_pProfile->m_aCluster[i].m_lLoad;
2607 strncpy(o_pClusterEntryArray[i].m_wsApplianceAlias,
2608 i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2609 KMS_MAX_ENTITY_ID);
2610 o_pClusterEntryArray[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2611 strncpy(o_pClusterEntryArray[i].m_wsApplianceNetworkAddress,
2612 i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2613 KMS_MAX_NETWORK_ADDRESS);
2614 o_pClusterEntryArray[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2615 strncpy(o_pClusterEntryArray[i].m_wsApplianceSiteID,
2616 i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2617 KMS_MAX_ENTITY_SITE_ID);
2618 o_pClusterEntryArray[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2619 strncpy(o_pClusterEntryArray[i].m_sKMAVersion, i_pProfile->m_aCluster[i].m_sKMAVersion,
2620 KMS_MAX_VERSION_LENGTH);
2621 o_pClusterEntryArray[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2622 }
2623
2624 i_pProfile->m_iLastClusterDiscoveryTime = K_GetTickCount() / 1000;
2625 i_pProfile->m_bIsClusterDiscoveryCalled = true;
2626
2627 if ( bPersistClusterConfig )
2628 {
2629 bSuccess = StoreCluster(i_pProfile);
2630 if (!bSuccess)
2631 {
2632 Log(AUDIT_CLIENT_GetClusterInformation,
2633 NULL,
2634 NULL,
2635 "Could not store cluster");
2636 }
2637 }
2638 }
2639 }
2640
2641 // cleanup
2642 if (pstSoap)
2643 {
2644 soap_destroy(pstSoap);
2645 soap_end(pstSoap);
2646 if (!bSuccess)
2647 {
2648 soap_free(pstSoap);
2649 }
2650 else
2651 {
2652 // we want to persist discovery soap runtime to avoid ssl handshakes so soap_free() is not called
2653 }
2654 }
2655
2656 // if we're enrolled but cannot get cluster information from an appliance, then we'll try to load
2657 // it from the profile
2658 if ( !bSuccess && i_pProfile->m_iEnrolled )
2659 {
2660 int bClusterInformationFound = false;
2661
2662 bSuccess = LoadClusterInformation( i_pProfile, bClusterInformationFound );
2663
2664 if ( bSuccess && bClusterInformationFound )
2665 {
2666 Log(AUDIT_CLIENT_GetClusterInformation,
2667 NULL,
2668 NULL,
2669 "Using persisted cluster information");
2670
2671 strncpy(o_wsEntitySiteID, i_pProfile->m_wsEntitySiteID, i_iEntitySiteIDSize-1);
2672 o_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2673
2674 // fill the array specified by the caller
2675 *o_pApplianceNum = i_pProfile->m_iClusterNum;
2676 for (int i = 0; i < i_pProfile->m_iClusterNum; i++)
2677 {
2678 o_pClusterEntryArray[i].m_lApplianceID = i_pProfile->m_aCluster[i].m_lApplianceID;
2679 o_pClusterEntryArray[i].m_iEnabled = i_pProfile->m_aCluster[i].m_iEnabled;
2680 o_pClusterEntryArray[i].m_iResponding = TRUE; // since cluster info comes from a file, set it to TRUE
2681
2682 o_pClusterEntryArray[i].m_lLoad = i_pProfile->m_aCluster[i].m_lLoad;
2683 strncpy(o_pClusterEntryArray[i].m_wsApplianceAlias,
2684 i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2685 KMS_MAX_ENTITY_ID);
2686 o_pClusterEntryArray[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2687 strncpy(o_pClusterEntryArray[i].m_wsApplianceNetworkAddress,
2688 i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2689 KMS_MAX_NETWORK_ADDRESS);
2690 o_pClusterEntryArray[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2691 strncpy(o_pClusterEntryArray[i].m_wsApplianceSiteID,
2692 i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2693 KMS_MAX_ENTITY_SITE_ID);
2694 o_pClusterEntryArray[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2695 strncpy(o_pClusterEntryArray[i].m_sKMAVersion,
2696 i_pProfile->m_aCluster[i].m_sKMAVersion,
2697 KMS_MAX_VERSION_LENGTH);
2698 o_pClusterEntryArray[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2699 }
2700
2701 i_pProfile->m_iLastClusterDiscoveryTime = K_GetTickCount() / 1000;
2702 }
2703 else if ( bSuccess && !bClusterInformationFound )
2704 {
2705 // if we're here, then we need to return an error
2706 bSuccess = false;
2707 }
2708 }
2709
2710 return bSuccess;
2711 }
2712
KMSClient_NoFIPSCompatibleKMAs(const KMSClientProfile * const i_pProfile)2713 bool KMSClient_NoFIPSCompatibleKMAs(const KMSClientProfile * const i_pProfile)
2714 {
2715 bool bNoFIPScompatibleKMA = true;
2716 for (int i=0; i < i_pProfile->m_iClusterNum; i++)
2717 {
2718 if ( FIPScompatibleKMA(i_pProfile->m_aCluster[i].m_sKMAVersion))
2719 {
2720 bNoFIPScompatibleKMA = false;
2721 break;
2722 }
2723 }
2724 return bNoFIPScompatibleKMA;
2725 }
2726
2727 /*---------------------------------------------------------------------------
2728 * Function: KMSClient_SelectAppliance
2729 *
2730 *--------------------------------------------------------------------------*/
KMSClient_SelectAppliance(KMSClientProfile * i_pProfile,utf8char * i_wsApplianceAddress)2731 bool KMSClient_SelectAppliance(KMSClientProfile *i_pProfile,
2732 utf8char *i_wsApplianceAddress)
2733 {
2734 FATAL_ASSERT(i_pProfile);
2735 FATAL_ASSERT(i_wsApplianceAddress);
2736
2737 CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
2738
2739 bool bSuccess = true;
2740
2741 if(strlen(i_wsApplianceAddress) >= KMS_MAX_NETWORK_ADDRESS)
2742 {
2743 LogError(i_pProfile,AUDIT_CLIENT_SELECT_APPLIANCE,
2744 NULL,
2745 NULL,
2746 "Appliance Address too large" );
2747 bSuccess = false;
2748 }
2749
2750 if(bSuccess)
2751 {
2752 strncpy(i_pProfile->m_wsApplianceAddress,
2753 i_wsApplianceAddress,
2754 KMS_MAX_NETWORK_ADDRESS);
2755 i_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
2756 }
2757
2758 bSuccess = StoreConfig( i_pProfile );
2759
2760 return bSuccess;
2761 }
2762
KMSClient_ProfileLoaded(KMSClientProfile * i_pProfile)2763 bool KMSClient_ProfileLoaded( KMSClientProfile *i_pProfile )
2764 {
2765
2766 #if defined(DEBUG) && defined(METAWARE)
2767 log_printf ("profile: %x", i_pProfile);
2768 log_printf ("profile: enrolled %x", i_pProfile->m_iEnrolled);
2769 log_printf ("profile: version %x", i_pProfile->m_iVersion);
2770 #endif
2771
2772 // more extensive tests could be performed but this should suffice
2773 if ( i_pProfile &&
2774 i_pProfile->m_iEnrolled &&
2775 i_pProfile->m_iVersion == KMS_AGENT_VERSION )
2776 {
2777 return true;
2778 }
2779 else
2780 {
2781 return false;
2782 }
2783 }
2784
2785 /*---------------------------------------------------------------------------
2786 * Function: KMSClient_DeleteProfile
2787 *
2788 *--------------------------------------------------------------------------*/
KMSClient_DeleteProfile(utf8char * i_wsProfileName)2789 bool KMSClient_DeleteProfile(utf8char *i_wsProfileName)
2790 {
2791 FATAL_ASSERT( i_wsProfileName && (strlen(i_wsProfileName) > 0) );
2792
2793 bool bSuccess = true;
2794
2795 if (ProfileExists(g_wsWorkingDirectory, /* pass in default */
2796 i_wsProfileName))
2797 {
2798 bSuccess = DeleteStorageProfile(i_wsProfileName);
2799 }
2800
2801 return bSuccess;
2802 }
2803
2804 /*---------------------------------------------------------------------------
2805 * Function: KMSClient_UnloadProfile
2806 *
2807 *--------------------------------------------------------------------------*/
KMSClient_UnloadProfile(KMSClientProfile * i_pProfile)2808 bool KMSClient_UnloadProfile(KMSClientProfile *i_pProfile)
2809 {
2810 if(i_pProfile != NULL && i_pProfile->m_pLock != NULL )
2811 {
2812 #ifdef KMSUSERPKCS12
2813 /* Delete the private client key file if it's still around */
2814 CleanupPrivateKeyFile(i_pProfile);
2815 #endif
2816 if (i_pProfile->m_pAgentLoadBalancer != NULL)
2817 {
2818 delete reinterpret_cast
2819 <CAgentLoadBalancer *> (i_pProfile->m_pAgentLoadBalancer);
2820 }
2821 if (i_pProfile->m_pDataUnitCache != NULL)
2822 {
2823 delete reinterpret_cast<CDataUnitCache *> (i_pProfile->m_pDataUnitCache);
2824 }
2825 K_DestroyMutex((K_MUTEX_HANDLE)i_pProfile->m_pLock);
2826 i_pProfile->m_pLock = 0;
2827
2828 if ( i_pProfile->m_pvSoap )
2829 {
2830 soap_destroy( (struct soap*)i_pProfile->m_pvSoap );
2831 soap_end( (struct soap*)i_pProfile->m_pvSoap );
2832 soap_done( (struct soap*)i_pProfile->m_pvSoap );
2833
2834 free( (struct soap*)i_pProfile->m_pvSoap );
2835 i_pProfile->m_pvSoap = 0;
2836 }
2837
2838 if ( i_pProfile->m_pvDiscoverySoap)
2839 {
2840 soap_destroy( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2841 soap_end( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2842 soap_done( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2843
2844 free( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2845 i_pProfile->m_pvDiscoverySoap = 0;
2846 }
2847 }
2848
2849 i_pProfile->m_iEnrolled = FALSE;
2850
2851 return true; /* always return true, maybe there are cases which return false in the future */
2852 }
2853
FIPScompatibleKMA(const char * const i_sKMAVersion)2854 bool FIPScompatibleKMA(
2855 const char * const i_sKMAVersion) {
2856 return (strcmp(i_sKMAVersion,
2857 FIPS_COMPATIBLE_KMA_VERSION) >= 0);
2858 }
2859
2860 #ifdef KMSUSERPKCS12
2861 extern "C"
2862 KMS_AGENT_STATUS
KMSAgent_GetProfileStatus(char * i_pProfileName,KMSAGENT_PROFILE_FLAGS * flags)2863 KMSAgent_GetProfileStatus(
2864 char* i_pProfileName,
2865 KMSAGENT_PROFILE_FLAGS *flags)
2866 {
2867 /*
2868 * Determine how "initialized" the KMS token is by checking for
2869 * the profile config file and also the entity key container (pkcs#12).
2870 */
2871 if (ProfileExists(g_wsWorkingDirectory, i_pProfileName)) {
2872 *flags |= KMSAGENT_PROFILE_EXISTS_FLAG;
2873 if (ClientKeyP12Exists(i_pProfileName))
2874 *flags |= KMSAGENT_CLIENTKEY_EXISTS_FLAG;
2875 }
2876 return (KMS_AGENT_STATUS_OK);
2877 }
2878 #endif
2879