KMSClientProfile.cpp revision 4f14b0f29aa144cc03efdde5508ae126ae197acf
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <stdio.h>
#include <errno.h>
#include "KMSAgent_direct.h"
#endif
#include <string.h>
#include "KMSClientProfile.h"
#include "KMSAgent.h"
#include "KMS_CAStub.h"
#include "KMS_CertificateStub.h"
#include "KMS_DiscoveryStub.h"
#include "KMSClientProfileImpl.h"
#include "KMSAuditLogger.h"
#include "KMSAgentSoapUtilities.h"
#include "KMSAgentStringUtilities.h"
#include "KMSAgentPKICommon.h" // must be before agentstorage
#include "stdsoap2.h"
#include "KMSAgentStorage.h" // uses KMSClientProfile
#include "KMSAgentWebServiceNamespaces.h"
#include "k_setupssl.h"
#include "KMSAgentChallenge.h"
#include "KMSAgentCryptoUtilities.h"
#include "ApplianceParameters.h"
#include "AutoMutex.h"
#include "KMSAgentLoadBalancer.h"
#include "KMSAgentDataUnitCache.h"
#include "ClientSoapFaultCodes.h"
#ifdef METAWARE
#include "debug.h"
#include "sizet.h"
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#include "literals.h"
#endif
#include "KMSAgentAESKeyWrap.h"
#include "debug.h"
#endif
#include "KMSAuditLogger.h"
#include "KMSClientProfileImpl.h"
#ifdef METAWARE
extern "C" void
... );
#endif
bool g_bUseFileLog = false;
static bool InitializeLogging(
const utf8cstr i_wsWorkingDirectory,
int i_bUseFileLog )
{
bool bFileLogSuccess = true;
g_bUseFileLog = ( i_bUseFileLog != 0 );
// InitializeFileLogging must always be called,
// because the file is always used by FATALs.
return bFileLogSuccess;
}
static void FinalizeLogging()
{
// FinalizeFileLogging must always be called,
// because the file is always used by FATALs.
return;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_InitializeLibrary
*
*--------------------------------------------------------------------------*/
const utf8cstr i_wsWorkingDirectory,
int i_bUseFileLog)
{
bool bSuccess;
log_printf("KMSClient_InitializeLibrary : ENTERING");
#endif
// setup SSL
if(!bSuccess)
{
return false;
}
log_printf("KMSClient_InitializeLibrary : set current directory");
#endif
// if i_wsWorkingDirectory is null, caller means current directory
if ( i_wsWorkingDirectory != NULL )
{
log_printf("KMSClient_InitializeLibrary : check working directory");
#endif
// string is there but is empty or junk
if (strlen(i_wsWorkingDirectory) <= 0)
{
}
{
return false;
}
log_printf("KMSClient_InitializeLibrary : set global working directory");
#endif
// set global working directory to input
}
else
{
}
log_printf("KMSClient_InitializeLibrary : Initialize logging");
#endif
// initialize file logging
return bSuccess;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_FinalizeLibrary
*--------------------------------------------------------------------------*/
bool KMSClient_FinalizeLibrary()
{
log_printf("KMSClient_FinalizeLibrary : ENTERING");
#endif
K_CleanupSSL();
return true; /* always */
}
int LogError_lastErrno;
/**
* Construct a message for the KMSAuditLogger and store the message
* in the profile as the last error message.
*/
int i_iErrno,
const char* i_sOperation,
const char* i_sEntityID,
const char* i_sNetworkAddress,
const char* i_sMessage )
{
// save for caller's use - this shouldn't be a global, but I don't
// want this as an item in the profile as I don't want it persisted
// log the message to a data file (and internal logs)
#ifndef METAWARE
if ( g_bUseFileLog )
#endif
{
}
#ifdef METAWARE
/* print this to the T10000/9840 VOP */
/* NOTE the \n is important to VOP - leave it in */
tnMsg("`msg`KMS2.0:msg#=%i,op=%s\r\n",
tnMsg("`msg`msg=%s,eid=%s,addr=%s\r\n",
#endif
// copy the error message into the profile (for later reference)
// make sure to NUL out the end
if ( i_sEntityID )
{
}
if ( i_sNetworkAddress )
{
",Address=",
}
if ( i_sMessage )
{
",Msg=",
}
// make sure to NUL out the end
}
// see KMSClientProfileImpl.h
bool SSL_InvalidCertificate (const char * const i_sErrorString)
{
if (
// OpenSSL generates this msg
{
return true;
}
return false;
}
// see KMSClientProfileImpl.h
{
// The Client Soap Fault Code returned by the KMA
// may be at the start of i_sErrorString or immediately
// follwing "SoapFaultString=" depending on the caller's
// string
int iErrorCode;
if ( sFaultstringStart )
{
}
else
{
// This may be zero if there is no error code at the start of the string.
}
// the following is commented out so the former check can be observed. This check is no longer
// made since invalid certificate failures may be due to a KMA that is behind on
// replication updates hence failover would succeed.
// if (
// // OpenSSL generates this msg
// SSL_InvalidCertificate(i_sErrorString))
// {
// return false;
// }
if (
// when the KMA is locked
// KMS 2.2 change when the KMA is locked
// KMS 2.2 change for core security internal error
// if the KMA's pre-gen'd key pool is depleted
// if the KMA's HSM is broke and the KMA is in FIPS mode
// when the server is too slow
// The Appliance is powered down, or is not reachable
// SOAP EOF
// Appliance server software is not running (while Appliance machine is OK)
// If the server has an internal error but still responds
// OpenSSL protocol errors (Note: the SSL_ERROR_SSL may be due
// to invalid client-side values, but for now it's used as a
// catch-all; a side-effect is that any actual invalid client-side
// value will cause one audit log entry to be created on each
// Appliance in the cluster).
"Error observed by underlying BIO: No error" )
"EOF was observed that violates the protocol" )
"SSL_ERROR_SSL" ) )
{
return true;
}
#ifndef WIN32
// check for errno values that imply connection problems to the server
switch (i_iErrno)
{
case ECONNABORTED : return true; // Connection aborted.
case ECONNREFUSED : return true; // Connection refused.
case ECONNRESET : return true; // Connection reset.
case EHOSTUNREACH : return true; // Host is unreachable.
case ENETDOWN : return true; // Network is down.
case ENETRESET : return true; // Connection aborted by network.
case ENETUNREACH : return true; // Network unreachable.
case ENOPROTOOPT : return true; // Protocol not available.
#ifndef METAWARE
case ETIME : return true; // Stream ioctl() timeout.
#endif
case ETIMEDOUT : return true; // Connection timed out.
}
#endif
// at this point we conclude its a client side issue
return false;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_GetLastErrorMessage
*
*--------------------------------------------------------------------------*/
// extern "C"
{
CAutoMutex oAutoMutex( 0 );
if ( i_pProfile->m_pLock )
{
}
return i_pProfile->m_wsErrorString;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_RetrieveEntityCertificate
* Get the Root CA Certificate and store it into the profile
*--------------------------------------------------------------------------*/
static bool KMSClient_RetrieveEntityCertificate(
char* const o_sHexHashedPassphrase )
{
log_printf("KMSClient_RetrieveEntityCertificate : entered");
#endif
bool bSuccess = true;
bool bTryFailOver = false;
{
#endif
NULL,
NULL,
"malloc failure for pstCASoap" );
return false;
}
// initialize the SOAP connection that will get the RootCA
soap_init2( pstCASoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
#ifdef METAWARE
#endif
CPrivateKey* pEntityPrivateKey = 0;
struct soap *pstCertificateSoap;
if(pstCertificateSoap == NULL)
{
#if defined(METAWARE)
log_printf("Malloc %x pstCertificateSoap returned null\n",
sizeof(struct soap));
#endif
return false;
}
// initialize the SOAP connection that will get the Certificate
soap_init2( pstCertificateSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
#ifdef METAWARE
#endif
log_printf("KMSClient_RetrieveEntityCertificate : call KMS_CA__RetrieveRootCACertificate");
#endif
// get the server's URL that will provide SOAP services
do
{
bSuccess = true;
bTryFailOver = false;
bool bFailedOnRetrieveRootCA = false;
const char* sURL = 0;
if ( bSuccess )
{
if ( !sURL )
{
bSuccess = false;
}
}
if ( bSuccess )
{
}
// SOAP CALL - retrieve Root CA Certificate from the Server
struct KMS_CA::
if ( bSuccess )
{
log_printf("KMSClient_RetrieveCertificate : call KMS_CA__RetrieveRootCACertificate again");
#endif
bSuccess =
NULL,
if ( !bSuccess )
{
NULL,
bFailedOnRetrieveRootCA = true;
}
}
else
{
log_printf("!bSuccess 1\n");
}
#endif
// Validate the SOAP response
if ( bSuccess )
{
{
bSuccess = false;
NULL,
NULL);
}
else
{
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 2\n");
}
#endif
// build our RootCACertificate object
if ( bSuccess )
{
pRootCACertificate = new CCertificate;
// make sure the new was successful
bSuccess = ( pRootCACertificate != 0 );
}
else
{
log_printf("!bSuccess 3\n");
}
#endif
if ( bSuccess )
{
// OVERLOADED Load method - 3 parameters means
// recall from BUFFER
bSuccess =
PKI_FORMAT ); // ignored
if( !bSuccess )
{
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 4\n");
}
#endif
if ( bSuccess )
{
// save the built CACertificate object to a FILE (i_pProfile gets the
// persistent handle to that file)
if ( !bSuccess )
{
NULL,
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 5\n");
}
#endif
//-------------------------------
// Initialize SSL - use SERVER AUTH
//-------------------------------
if ( bSuccess )
{
// SERVER_AUTHENTICATION needs just the pstCertificateSoap
bSuccess =
i_pProfile, // in ->m_wsProfileName,->m_sHexHashedPassphrase
pstCertificateSoap, // in - soap structure
SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION // in - flags
) == SOAP_OK;
if ( !bSuccess )
{
NULL,
}
}
else
{
log_printf("!bSuccess 6\n");
}
#endif
// hash the passphrase passed in
if ( bSuccess )
{
if ( !bSuccess )
{
NULL,
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 7\n");
}
#endif
// copy received Root CA into buffer for input
// into challenge-response computation
unsigned char aRootCACertificate[MAX_CERT_SIZE];
if ( bSuccess )
{
// OVERLOADED save method - save iRootCACertificateLength to aRootCACertificate
// buffer
PKI_FORMAT );
if ( !bSuccess )
{
NULL,
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 8\n");
}
#endif
// respond to server's challenge
unsigned char aAuthenticationSecret[AUTHENTICATION_SECRET_LENGTH];
unsigned char
if ( bSuccess )
{
sHexAuthenticationSecret, NULL ) );
// client authentication response
if ( !bSuccess )
{
NULL,
NULL,
NULL);
}
}
else
{
log_printf("!bSuccess 9\n");
}
#endif
if ( bSuccess )
{
(unsigned char*)soap_malloc(
{
}
else
{
bSuccess = false;
}
}
else
{
log_printf("!bSuccess 10\n");
}
#endif
// generate challenge nonce
if ( bSuccess )
{
(unsigned char*)soap_malloc( pstCertificateSoap,
}
else
{
log_printf("!bSuccess 11\n");
}
#endif
if ( bSuccess )
{
}
else
{
log_printf("!bSuccess 12\n");
}
#endif
if ( bSuccess )
{
if ( !sURL )
{
bSuccess = false;
}
}
else
{
log_printf("!bSuccess 13\n");
}
#endif
// Verify that the same URL is used for Root CA Certificate
// retrieval as for Entity Certificate retrieval
if ( bSuccess )
{
sTempCAURL[KMS_MAX_URL] = 0;
sTempAgentURL[KMS_MAX_URL] = 0;
sRetrieveAgentCertificateURL ) == 0 );
}
else
{
log_printf("!bSuccess 14\n");
}
#endif
// SOAP - retrieve ENTITY Certificate, passing the challenge response,
// a challenge to the server and get back the server's response
if ( bSuccess )
{
bSuccess =
sURL,
NULL,
if( !bSuccess )
{
NULL,
}
}
else
{
log_printf("!bSuccess 15\n");
}
#endif
// Validate the response structure
if ( bSuccess )
{
WrappedPrivateKeyMaterial.__ptr == 0 )
{
bSuccess = false;
NULL,
NULL );
}
else
{
NULL,
NULL );
}
}
else
{
log_printf("!bSuccess 16\n");
}
#endif
// if valid, calculate the correct challenge-response
unsigned char
if ( bSuccess )
{
}
else
{
log_printf("!bSuccess 17\n");
}
#endif
// if successful, check if the server provided the correct challenge-response
if ( bSuccess )
{
if ( 0 != memcmp(
{
bSuccess = false;
NULL,
NULL );
}
}
else
{
log_printf("!bSuccess 18\n");
}
#endif
if ( bSuccess )
{
pEntityCertificate = new CCertificate;
// if certificate was obtained
bSuccess = ( pEntityCertificate != 0 );
}
else
{
log_printf("!bSuccess 19\n");
}
#endif
if ( bSuccess )
{
// Load(recall) the signed certificate using OVERLOADED load method
// 3 parameters means load from a buffer
PKI_FORMAT );
if ( !bSuccess )
{
NULL,
NULL );
}
}
else
{
log_printf("!bSuccess 20\n");
}
#endif
if ( bSuccess )
{
pEntityPrivateKey = new CPrivateKey;
bSuccess = ( pEntityPrivateKey != 0 );
}
else
{
log_printf("!bSuccess 21\n");
}
#endif
if ( bSuccess )
{
// Load the Private Key using OVERLOADED Load method - 3 parameters
// means load from a buffer
// TODO: change this when certificate service supports requesting unwrapped private keys
NULL,
PKI_FORMAT );
if (!bSuccess )
{
NULL,
NULL );
}
}
if ( bSuccess )
{
// store PKI certificates and unwrapped private key
#ifdef KMSUSERPKCS12
#else
#endif
);
#ifdef KMSUSERPKCS12
if (bSuccess) {
/*
* Write out the cert and key individually so GetPKIcerts
* can use them.
*/
}
#endif
}
if ( !bSuccess )
{
if (pRootCACertificate)
{
delete pRootCACertificate;
}
if (pEntityCertificate)
{
delete pEntityCertificate;
}
if (pEntityPrivateKey)
{
delete pEntityPrivateKey;
}
if ( bTryFailOver )
{
}
}
}
// certs are now persisted so free up space
if ( bSuccess )
{
delete pRootCACertificate;
delete pEntityCertificate;
delete pEntityPrivateKey;
}
// Clean up SOAP resources for pstCASoap
// Clean up SOAP resources for pstCertificateSoap
return bSuccess;
}
/*--------------------------------------------------------------------------
* LoadClusterInformation
* calls GetCluster - that's it.
* If there is no cluster file, this function will return true,
* but o_bClusterInformationFound will be false.
*-------------------------------------------------------------------------*/
int& o_bClusterInformationFound )
{
o_bClusterInformationFound = false;
}
/*--------------------------------------------------------------------------
* EnrollAgent
* calls functions to perform enrollment and save PKI info to persistent storage
* stores configuration in persistent storage
*-------------------------------------------------------------------------*/
{
bool bSuccess = true;
// see KMSAgentCryptoUtilities for HASH_LENGTH, aka KMS_MAX_HASH_SIZE
if ( bSuccess )
{
// performs enrollment and saves PKI info to persistent storage
// KMSClient_RetrieveCertificate logs errors
}
if (bSuccess)
{
2*KMS_MAX_HASH_SIZE );
// persist the profile now updated with the hashed passphrase
if (!bSuccess)
{
NULL,
"store config failed following enrollment" );
}
}
return bSuccess;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_LoadProfile
*
*--------------------------------------------------------------------------*/
bool KMSClient_LoadProfile(
int i_iFailOverLimit,
int i_eKMSmode)
{
bool bSuccess = true;
log_printf("KMSClient_LoadProfile : entered");
#endif
// create lock
if (bSuccess)
{
bSuccess =
K_SYS_OK );
}
// initialize profile with parameters
// if the file isn't found, create a new one
#ifdef KMSUSERPKCS12
/*
* Fix logic for determining if this request is for enrollment.
* Look to see if the server cert and clientkey.p12 file exist.
* We always expect a password for Solaris which is used to
* validate that the user has access to the clientkey data by
* attempting to use it to open the PKCS12 file.
*/
#else
#endif
{
// when not enrolling a profile must exist
bSuccess = false;
NULL,
"Enrollment attempted but profile could not be found" );
}
// if the file isn't found, create a new one
if ( bSuccess && !bProfileExists )
{
}
// load profile.cfg file
if ( bSuccess )
{
}
// if profile settings changed then update the profile storage
if ( bSuccess &&
i_wsApplianceAddress, KMS_MAX_NETWORK_ADDRESS ) != 0 ||
))
{
}
// get PKI info from prior enrollment
if ( bSuccess && !bEnrolling )
{
#ifdef KMSUSERPKCS12
/*
* Decrypt the PKCS12 file with the client cert and key using
* the given password. If it fails, then return an auth failure
* status. If success, write the client cert and key to the client file
* so it can be used later by the SOAP SSL functions.
*/
if (!bSuccess) {
NULL,
"Enrollment Certificate and Private Key "\
"were not loaded from PKCS12" );
} else {
/*
* Write out the cert and key individually so GetPKIcerts
* can use them.
*/
if (!bSuccess) {
NULL,
"Enrollment Certificate and Private Key "\
"were not stored to file." );
}
}
delete pEntityCertificate;
delete pEntityPrivateKey;
#endif
if (bSuccess)
}
// if not enrolling then previously enrolled PKI info should now be initialized
if ( bSuccess && !bEnrolling &&
!io_pProfile->m_iEnrolled ))
{
bSuccess = false;
NULL,
"Enrollment Certificates and Private Key were not loaded from profile" );
}
io_pProfile->m_bIsClusterDiscoveryCalled = false;
// allocate main soap struct
if ( bSuccess )
{
if ( bSuccess )
{
(SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
#ifdef METAWARE
K_SetupCallbacks ( pstSoap );
#endif
}
else
{
log_printf("Malloc %x pstSoap returned null\n",
sizeof(struct soap));
#endif
}
}
// delete the existing cluster config if the input IP address
// does not match one already known to the cluster config
// Note that KMSClientProfile may be too large to fit on the stack, so we're
// going to put it on the heap.
bool bFound = false;
int i;
if ( bSuccess )
{
bSuccess = (pstTempProfile != 0);
#if defined(METAWARE)
if (!bSuccess)
log_printf("Malloc %x pstTempProfile returned null\n",
sizeof(KMSClientProfile));
#endif
}
int bClusterInformationFound = false;
if ( bSuccess )
{
}
// got cluster info from persistent storage
if ( bSuccess && bClusterInformationFound )
{
// see if address is a member of the remembered cluster or is a
// new kma, meaning this KMA joins the cluster as the
// discovery KMA.
for ( i = 0; i < pstTempProfile->m_iClusterNum; i++ )
{
KMS_MAX_NETWORK_ADDRESS) == 0);
if ( bFound )
{
break;
}
else
log_printf ("KMSClient_LoadProfile : Appliance Address doesn't match");
#endif
}
if ( !bFound )
{
log_printf ("KMSClient_LoadProfile : delete cluster");
#endif
char msg[256];
"KMSClientProfile.LoadProfile(): deleting previous cluster config, %s not found\n",
NULL,
msg );
}
else
{
// since address is a member of the persisted cluster copy the persisted cluster info to the profile
}
}
else
log_printf ("KMSClient_LoadProfile : no persisted cluster information");
#endif
if ( pstTempProfile )
{
log_printf ("KMSClient_LoadProfile : free the temporary profile");
#endif
free( pstTempProfile );
pstTempProfile = 0;
}
{
log_printf ("KMSClient_LoadProfile : call EnrollAgent");
#endif
// enroll the agent
}
else if (io_pProfile->m_iEnrolled)
log_printf ("KMSClient_LoadProfile : Already Enrolled");
#endif
if (bSuccess)
{
// Initialize SSL - use CLIENT AUTH
// CLIENT_AUTHENTICATION needs the pstSoap, and expects
// the profile io_pProfile to be full (have the other certificates
// and keypair)
if ( bSuccess )
{
bSuccess =
io_pProfile, // in/out
pstSoap, // out
SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION // in - flags
) == SOAP_OK;
if ( !bSuccess )
{
if (!bSuccess)
log_printf ("KMSClient_LoadProfile : K_soap_ssl_client_context failed");
#endif
NULL,
}
}
// discover the cluster
if ( bSuccess &&
{
sizeof(io_pProfile->m_wsEntitySiteID),
&(io_pProfile->m_iClusterNum),
KMS_MAX_CLUSTER_NUM) != 0 );
// KMSClient_GetClusterInformation logs errors
{
if (!bSuccess)
{
NULL,
NULL,
NULL );
}
}
}
if (!bSuccess)
log_printf ("KMSClient_LoadProfile : getClusterInformation failed");
#endif
#ifdef KMSUSERPKCS12
/*
* Once the SSL context is established, delete the
* private key file.
*/
(void) CleanupPrivateKeyFile(io_pProfile);
#endif
}
else if (!bSuccess)
log_printf ("KMSClient_LoadProfile : EnrollAgent failed");
#endif
if(pAgentLoadBalancer == NULL)
{
bSuccess = false;
}
if (!bSuccess)
log_printf ("KMSClient_LoadProfile : new CAgentLoadBalancer failed");
#endif
// create a data unit server affinity cache for Agents
if ( bSuccess )
{
}
if ( bSuccess )
{
log_printf ("KMSClient_LoadProfile : set version to KMS_AGENT_VERSION = %x",
#endif
// this is checked later by ProfileLoaded and is taken
// to indicate that the profile was correctly loaded
}
if( !bSuccess )
{
io_pProfile->m_pLock = 0;
if ( io_pProfile->m_pvSoap )
{
io_pProfile->m_pvSoap = 0;
{
}
{
}
}
log_printf ("KMSClient_LoadProfile : failed - returning");
#endif
}
return bSuccess;
}
/**
* compare cluster entries having equivalent KMA names (aka Appliance alias) and
* return true if equal. Note: KMANetworkAddress comparison is handled separately
*/
static bool EqualClusterEntry(
KMSClusterEntry const *i_pRight)
{
{
return false;
}
{
return false;
}
KMS_MAX_ENTITY_SITE_ID) != 0 )
{
return false;
}
// Note: we now minimize persistence of cluster changes by not saving
// whenever m_iResponding changes
return true;
}
/**
* @return true if the current address matches the provided IPv6Address
* when the i_bUseIPv6 arg is true, otherwise compare the current address
* with the IPv4Address. If i_bUseIPv6 then i_pCurrentAddress must be
* enclosed in brackets, i.e. as in RFC 2396.
*/
static bool EqualKMANetworkAddress (
bool i_bUseIPv6,
const char * const i_pIPv6Address,
const char * const i_pIPv4Address,
const char * const i_pCurrentAddress
)
{
bool bEqualAddress = true;
if ( i_pCurrentAddress == NULL )
{
return false;
}
if (i_bUseIPv6)
{
if ( i_pIPv6Address == NULL )
{
return false;
}
{
// remove prefix from address
*pLoc = '\0';
}
}
else
{
if ( i_pIPv4Address == NULL )
{
return false;
}
}
return bEqualAddress;
}
/**
* compares the profile's current cluster state with the filtered discover
* cluster response and returns true if the repsonse
* differs from i_pProfile->m_aCluster. A cluster has changed if the state of any
* cluster node has changed or if the set of cluster nodes has changed.
* The order of nodes is immaterial.
*/
static bool ClusterConfigChanged (
KMSClientProfile const *i_pProfile,
char * const i_sResponseEntitySiteID,
{
int i, j;
// cardinality check
if (i_pProfile->m_iClusterNum !=
{
return true;
}
// check if the agent's site ID changed
{
return true;
}
// for all KMAs in filtered response check if they exist unchanged in the profile
for (i = 0; i < i_pFilteredCluster->__size; i++)
{
bool bFound = false;
for (j = 0; j < i_pProfile->m_iClusterNum; j++)
{
KMS_MAX_ENTITY_ID) == 0)
{
bFound = true;
if (
&i_pProfile->m_aCluster[j]))
{
return true;
}
}
}
if ( !bFound )
{
return true;
}
}
return false;
}
/**
* returns true if the string is a valid IPv6 address syntactically
*/
static bool ValidIPv6KMAaddress( const char * const i_pIPAddress )
{
if ( strlen(i_pIPAddress) <= 0 )
{
return false;
}
// simple check
{
return true;
}
return false;
}
/**
*
*/
static void FreeFilteredCluster (
int iLimit )
{
int j = 0;
for (; j < iLimit; j++ )
{
}
}
/**
* filters the discover cluster response to be less than or equal to KMS_MAX_CLUSTER_NUM KMAs. The heuristic used to filter
* the response is the same as used by CAgentLoadBalancer::KMSClient_SortClusterArray(), FIPS compatibility, then within site,
* then responding and enabled KMAs.
* @param i_stResponse pointer to gsoap discover cluster service response
* @param io_stFilteredCluster pointer to gsoap discover cluster array to be populated with the filtered list of KMAs
* @return true on success and io_stFilteredCluster->__size less than or equal to KMS_MAX_CLUSTER_NUM,
* otherwise io_stFilteredCluster is undefined. io_stFilteredCluster->__ptr is populated with the array of elements
* malloc'd.
*/
static bool FilterCluster (struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse * const i_stResponse,
bool i_bFIPS,
{
/*
* do something like KMSAgentLoadBalancer:SortClusterArray() to the stResponse array
* return 1st KMS_MAX_CLUSTER_NUM entries and free the rest.
*/
io_stFilteredCluster->__ptr = reinterpret_cast < struct KMS_Discovery::KMS_Discovery_ClusterMember * >
sizeof (struct KMS_Discovery::KMS_Discovery_ClusterMember ) ) );
{
NULL,
NULL,
"calloc failed");
return false;
}
if (io_stFilteredCluster->__size <= 0)
{
NULL,
NULL,
"returned cluster size is not positive");
return false;
}
// copy response cluster members
for (int i = 0; i < io_stFilteredCluster->__size; i++)
{
bool bSuccess = true;
// allocate storage for the various struct member's arrays
io_stFilteredCluster->__ptr[i].KMANetworkAddress = reinterpret_cast <char *> (malloc(iKMANetworkAddressSize));
// KMAVersion is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
{
{
bSuccess = false;
}
}
else
{
}
// KMAHostNameIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
{
io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 = reinterpret_cast <char *> (malloc(iKMAHostNameIPv6Size));
{
bSuccess = false;
}
}
else
{
}
// KMANetworkAddressIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
{
iKMANetworkAddressIPv6Size = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6)+1;
io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 = reinterpret_cast <char *> (malloc(iKMANetworkAddressIPv6Size));
{
bSuccess = false;
}
}
else
{
}
!bSuccess )
{
// cleanup and return
NULL,
NULL,
"malloc failed" );
return false;
}
{
}
{
}
{
}
io_stFilteredCluster->__ptr[i].KMS_Discovery__Locked = i_stResponse->ArrayOfClusterMembers.__ptr[i].KMS_Discovery__Locked;
// set load to zero, KMA with version <= Build600 don't initialize
// the load field from the service network
{
}
else
{
}
io_stFilteredCluster->__ptr[i].Responding = i_stResponse->ArrayOfClusterMembers.__ptr[i].Responding;
if (!bSuccess)
{
NULL,
NULL,
"cluster member copy failed");
return false;
}
}
// is filtering necessary?
{
// no filtering required
return true;
}
else
{
char sMesg[100];
K_snprintf(sMesg, sizeof (sMesg), "DiscoverCluster returned %d KMAs, filtering to %d ...", io_stFilteredCluster->__size, KMS_MAX_CLUSTER_NUM);
NULL,
NULL,
sMesg);
}
// adjust loads according to availability, site and FIPS compatibility
{
int i = 0;
for (; i < io_stFilteredCluster->__size; i++)
{
{
}
i_stResponse->EntitySiteID) != 0)
{
}
if ( i_bFIPS &&
{
}
}
}
// sort ascending by load
// gnome sort: the simplest sort algoritm
{
int i = 0;
while (i < io_stFilteredCluster->__size)
{
{
i++;
}
else
{
}
}
}
// now filter the list, freeing memory allocated for copied elements that are not being retained
{
int i=KMS_MAX_CLUSTER_NUM;
for (; i < io_stFilteredCluster->__size; i++)
{
}
}
NULL,
NULL,
"success");
return true;
};
/*---------------------------------------------------------------------------
* Function: KMSClient_GetClusterInformation
*
*--------------------------------------------------------------------------*/
int i_iEntitySiteIDSize,
int *o_pApplianceNum,
{
bool bSuccess = true;
// set URL from the initial appliance address
log_printf("KMSClient_GetClusterInformation : entered");
#endif
// allocate and initialize a new soap env for the cluster discovery call
if ( !i_pProfile->m_iEnrolled )
{
bSuccess = false;
}
if ( bSuccess )
{
// allocate discovery soap runtime
{
/* soap_copy results in a segfault in sk_free() within libcrytpo.so
pstSoap = soap_copy( (soap*)i_pProfile->m_pvSoap );
*/
{
bSuccess = false;
}
else
{
) == SOAP_OK;
if ( !bSuccess )
{
NULL,
NULL,
"K_soap_ssl_client_context failed");
}
}
}
}
// Discovery
log_printf("KMSClient_GetClusterInformation : call KMS_Discovery_DiscoverCluster");
#endif
// SOAP - discover cluster
if ( bSuccess )
{
#ifdef DEBUG
int iStartTickCount = K_GetTickCount();
int iEndTickCount;
char sDiscoverTimeMsg[100];
#endif
bSuccess =
sURL,
NULL,
NULL,
stResponse ) == SOAP_OK;
#ifdef DEBUG
NULL,
#endif
if ( !bSuccess )
{
NULL,
{
// do not failover if error is client related
soap_destroy( pstSoap );
return false;
}
}
// If we did not succeed to Discover from the initial appliance,
// try to discover from other appliances that we know about that are enabled.
// Disabled Appliances are not attempted because they may have a stale view
// of the cluster. In particular, they themselves are not aware that they
// are disabled.
{
// Copy the profile's cluster array so that we don't have to lock the
// profile around a SOAP call
int j = 0;
int iClusterNum = 0;
if (!bSuccess)
log_printf("Malloc %x aCluster returned null\n",
sizeof(KMSClusterEntry) * KMS_MAX_CLUSTER_NUM);
#endif
if ( bSuccess )
{
sizeof(KMSClusterEntry) * iClusterNum );
// initialize to false since all KMAs could be disabled
bSuccess = false;
for ( j = 0; j < iClusterNum; j++ )
{
{
continue;
}
NULL,
"Failing over and trying this appliance");
// SOAP - discover cluster
bSuccess =
sURL,
NULL,
NULL,
stResponse ) == SOAP_OK;
if ( !bSuccess )
{
NULL,
}
else
{
// The discover succeeded
break;
}
}
}
if ( aCluster != 0 )
{
}
if ( bSuccess )
{
// Set the Profile's initial appliance to the Appliance
// that we just succeeded to Discover from. KMSClient_SelectAppliance()
// persists the updated config
}
}
}
if ( bSuccess )
{
{
bSuccess = false;
NULL,
NULL,
"returned site id size too large" );
}
}
// copy returned cluster information into i_pProfile->m_aCluster after
// filtering the cluster members to a list with size <= KMS_MAX_CLUSTER_NUM
if ( bSuccess )
{
if (!bSuccess )
{
NULL,
NULL,
"cluster response filtering failed" );
}
if(bSuccess)
{
int i;
// fill the aCluster array in the i_pProfile
for (i = 0; i < i_pProfile->m_iClusterNum; i++)
{
// if the m_wsApplianceAddress is IPv6 then we'll store
// KMA IPv6 addresses if they have one
{
// KMAs prior to 2.1, or 2.1 KMAs at rep schema < 10
// will not have IPv6 attributes in the soap response
{
'/');
{
// remove prefix from address
*pLoc = '\0';
}
else
{
}
}
else
{
// use the IPv4 address
}
}
else
{
}
{
}
else
{
}
{
}
else
{
}
}
// now release malloc'd storage from filtering the cluster response
// fill the array specified by the caller
for (i = 0; i < i_pProfile->m_iClusterNum; i++)
{
}
i_pProfile->m_bIsClusterDiscoveryCalled = true;
if ( bPersistClusterConfig )
{
if (!bSuccess)
{
NULL,
NULL,
"Could not store cluster");
}
}
}
}
// cleanup
if (pstSoap)
{
if (!bSuccess)
{
}
else
{
// we want to persist discovery soap runtime to avoid ssl handshakes so soap_free() is not called
}
}
// if we're enrolled but cannot get cluster information from an appliance, then we'll try to load
// it from the profile
{
int bClusterInformationFound = false;
if ( bSuccess && bClusterInformationFound )
{
NULL,
NULL,
"Using persisted cluster information");
// fill the array specified by the caller
for (int i = 0; i < i_pProfile->m_iClusterNum; i++)
{
o_pClusterEntryArray[i].m_iResponding = TRUE; // since cluster info comes from a file, set it to TRUE
}
}
else if ( bSuccess && !bClusterInformationFound )
{
// if we're here, then we need to return an error
bSuccess = false;
}
}
return bSuccess;
}
{
bool bNoFIPScompatibleKMA = true;
for (int i=0; i < i_pProfile->m_iClusterNum; i++)
{
{
bNoFIPScompatibleKMA = false;
break;
}
}
return bNoFIPScompatibleKMA;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_SelectAppliance
*
*--------------------------------------------------------------------------*/
{
bool bSuccess = true;
{
NULL,
NULL,
"Appliance Address too large" );
bSuccess = false;
}
if(bSuccess)
{
}
return bSuccess;
}
{
#endif
// more extensive tests could be performed but this should suffice
if ( i_pProfile &&
{
return true;
}
else
{
return false;
}
}
/*---------------------------------------------------------------------------
* Function: KMSClient_DeleteProfile
*
*--------------------------------------------------------------------------*/
{
bool bSuccess = true;
{
}
return bSuccess;
}
/*---------------------------------------------------------------------------
* Function: KMSClient_UnloadProfile
*
*--------------------------------------------------------------------------*/
{
{
#ifdef KMSUSERPKCS12
/* Delete the private client key file if it's still around */
#endif
{
delete reinterpret_cast
}
{
}
i_pProfile->m_pLock = 0;
if ( i_pProfile->m_pvSoap )
{
i_pProfile->m_pvSoap = 0;
}
if ( i_pProfile->m_pvDiscoverySoap)
{
i_pProfile->m_pvDiscoverySoap = 0;
}
}
return true; /* always return true, maybe there are cases which return false in the future */
}
bool FIPScompatibleKMA(
const char * const i_sKMAVersion) {
return (strcmp(i_sKMAVersion,
FIPS_COMPATIBLE_KMA_VERSION) >= 0);
}
#ifdef KMSUSERPKCS12
extern "C"
char* i_pProfileName,
{
/*
* Determine how "initialized" the KMS token is by checking for
* the profile config file and also the entity key container (pkcs#12).
*/
}
return (KMS_AGENT_STATUS_OK);
}
#endif