diff options
| author | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> | 2010-06-28 16:04:11 -0700 | 
|---|---|---|
| committer | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> | 2010-06-28 16:04:11 -0700 | 
| commit | 4f14b0f29aa144cc03efdde5508ae126ae197acf (patch) | |
| tree | 5292d99c7ec8374d412d58116e7bbc7279e72067 /usr/src/lib/libkmsagent/common/KMSAgent.cpp | |
| parent | 1e49577a7fcde812700ded04431b49d67cc57d6d (diff) | |
| download | illumos-joyent-4f14b0f29aa144cc03efdde5508ae126ae197acf.tar.gz | |
PSARC 2010/195 PKCS11 KMS Provider
6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
Diffstat (limited to 'usr/src/lib/libkmsagent/common/KMSAgent.cpp')
| -rw-r--r-- | usr/src/lib/libkmsagent/common/KMSAgent.cpp | 3851 | 
1 files changed, 3851 insertions, 0 deletions
| diff --git a/usr/src/lib/libkmsagent/common/KMSAgent.cpp b/usr/src/lib/libkmsagent/common/KMSAgent.cpp new file mode 100644 index 0000000000..3d34ea571f --- /dev/null +++ b/usr/src/lib/libkmsagent/common/KMSAgent.cpp @@ -0,0 +1,3851 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 + */ + +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/** + * \file KMSAgent.cpp + */ + +#ifdef WIN32 +#define _WIN32_WINNT 0x0400 +#include <windows.h> +#include <process.h> +#endif + +#include <stdlib.h> + +#include "KMSClientProfile.h" + +#include "KMS_AgentStub.h" +#include "KMS_DiscoveryStub.h" + +#include "KMSClientProfileImpl.h" +#include "KMSAgent.h" +#include "KMSAuditLogger.h" +#include "KMSAgentSoapUtilities.h" +#include "KMSAgentStringUtilities.h" +#include "KMSAgentPKICommon.h" +#include "KMSAgentLoadBalancer.h" + +#include "KMSAgentWebServiceNamespaces.h" +#include "k_setupssl.h" + +#include "ApplianceParameters.h" + +#include "AutoMutex.h" +#include "KMSAgentKeyCallout.h" + +#include "KMSAgentLoadBalancer.h" +#include "KMSAgentDataUnitCache.h" + +#ifdef K_SOLARIS_PLATFORM +#include "KMSAgentStorage.h" +#endif + +#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; +#endif + +#include "KMSAgentAESKeyWrap.h" +#include "KMSAgentKnownAnswerTests.h" + +#if defined(METAWARE) && defined(DEBUG_RETURNS) +extern "C" void ecpt_trace_msg (ECPT_TRACE_ENTRY*, char*, ...); + +#define RETURN(a) { ecpt_trace_msg( trace,"(returned=%x)",(a));  return(a);  } + +#else +#define RETURN(a) return(a) +#endif + +/* KMS_AGENT_VERSION_STRING  gets passed in via compilation flags */ +extern "C" const char KMSAgent_Version[KMS_MAX_VERSION_LENGTH + 1] = KMS_AGENT_VERSION_STRING; + + +/* The following enum and structs are used for QueryParameters in + * ListKeyGroup. Since they are only used in implementation code, + * so they are not in the header file in order to hide these details + */ + + +/*---------------------------Start Query Parameters Declartion -------- */ + +#define KMS_MAX_AGENT_FILTER_PARAMETERS     10 + +enum KMSAgent_SortOrder +{ +    SORT_ORDER_ASCENDING = 0, +    SORT_ORDER_DESCENDING +}; + +enum KMSAgent_FilterOperator +{ +    FILTER_OPERATOR_EQUAL = 0, +    FILTER_OPERATOR_NOT_EQUAL, +    FILTER_OPERATOR_GREATER_THAN, +    FILTER_OPERATOR_LESS_THAN, +    FILTER_OPERATOR_GREATER_THAN_OR_EQUAL, +    FILTER_OPERATOR_LESS_THAN_OR_EQUAL, +    FILTER_OPERATOR_STARTS_WITH +}; + +struct KMSAgent_FilterParameters +{ +    utf8char m_wsFieldName[KMS_MAX_FIELD_NAME + 1]; +    enum KMSAgent_FilterOperator m_eFilterOperator; +    utf8char m_wsFieldValue[KMS_MAX_FIELD_VALUE + 1]; +}; + +struct KMSAgent_QueryParameters +{ +    utf8char m_wsSortFieldName[KMS_MAX_FIELD_NAME + 1]; +    enum KMSAgent_SortOrder m_eSortOrder; + +    struct KMSAgent_FilterParameters m_aFilterParameters[KMS_MAX_AGENT_FILTER_PARAMETERS]; +    int m_iSizeFilterParameters; + +    utf8char m_wsPreviousPageLastIDValue[KMS_MAX_ID + 1]; +    utf8char m_wsPreviousPageLastSortFieldValue[KMS_MAX_FIELD_VALUE + 1]; +}; + +/*---------------------------End Of Query Parameters Declaration -------- */ + +#ifdef METAWARE +int CAgentLoadBalancer::FailOver (int i_iFailedApplianceIndex, +                                  struct soap *i_pstSoap); +#endif + +extern const char * KMSAgent_GetVersion () +{ +    return (KMSAgent_Version); +} + +static bool CopyQueryParametersFromRequest +( + struct soap *i_pstSoap, + int i_iPageSize, + struct KMS_Agent::KMS_Agent__QueryParameters *i_pQueryParameters, + struct KMSAgent_QueryParameters *i_pSourceQueryParameters + ) +{ + +    // set page size +    i_pQueryParameters->NextPageSize = i_iPageSize; + +    // copy sort field name +    i_pQueryParameters->SortFieldName = (char *) +            soap_malloc(i_pstSoap, +            sizeof (i_pSourceQueryParameters->m_wsSortFieldName)); +    if (i_pQueryParameters->SortFieldName == NULL) +    { +        return (false); +    } +    strncpy(i_pQueryParameters->SortFieldName, +            i_pSourceQueryParameters->m_wsSortFieldName, +            sizeof (i_pSourceQueryParameters->m_wsSortFieldName)); +    i_pQueryParameters->SortFieldName[sizeof (i_pSourceQueryParameters->m_wsSortFieldName)-1] = 0; + +    // sort order +    i_pQueryParameters->SortOrder = +            (enum KMS_Agent::KMS_Agent__SortOrder)i_pSourceQueryParameters->m_eSortOrder; + +    // copy filter parameters +    i_pQueryParameters->FilterParameters.__size = +            i_pSourceQueryParameters->m_iSizeFilterParameters; + +    if (i_pQueryParameters->FilterParameters.__size > 0) +    { +        i_pQueryParameters-> +                FilterParameters.__ptr = +                (struct KMS_Agent::KMS_Agent__FilterParameters *)soap_malloc +                (i_pstSoap, +                sizeof (KMS_Agent::KMS_Agent__FilterParameters) * +                i_pQueryParameters->FilterParameters.__size); + +        if (i_pQueryParameters->FilterParameters.__ptr == NULL) +        { +            return (false); +        } +    } +    else +    { +        i_pQueryParameters->FilterParameters.__ptr = NULL; +    } + +    for (int i = 0; i < i_pSourceQueryParameters->m_iSizeFilterParameters; i++) +    { +        struct KMS_Agent::KMS_Agent__FilterParameters *pParameters; + +        pParameters = &(i_pQueryParameters->FilterParameters.__ptr[i]); + +        // copy field name +        pParameters->FieldName = ( +                utf8cstr) soap_malloc(i_pstSoap, +                sizeof (i_pSourceQueryParameters-> +                m_aFilterParameters[i].m_wsFieldName)); +        if (pParameters->FieldName == NULL) +        { +            return (false); +        } + +        strncpy(pParameters->FieldName, +                i_pSourceQueryParameters->m_aFilterParameters[i].m_wsFieldName, +                sizeof (i_pSourceQueryParameters-> +                    m_aFilterParameters[i].m_wsFieldName)); +        pParameters->FieldName[sizeof (i_pSourceQueryParameters-> +                    m_aFilterParameters[i].m_wsFieldName)-1] = '\0'; + +        // copy field value +        pParameters->FieldValue = +                (utf8cstr) soap_malloc +                (i_pstSoap, +                sizeof (i_pSourceQueryParameters->m_aFilterParameters[i].m_wsFieldValue)); +        if (pParameters->FieldValue == NULL) +        { +            return (false); +        } + +        strncpy(pParameters->FieldValue, +                i_pSourceQueryParameters->m_aFilterParameters[i].m_wsFieldValue, +                sizeof (i_pSourceQueryParameters->m_aFilterParameters[i].m_wsFieldValue)); +        pParameters->FieldValue[sizeof (i_pSourceQueryParameters->m_aFilterParameters[i].m_wsFieldValue)-1] = '\0'; + +        // copy FilterOperator +        pParameters->FilterOperator = +                (KMS_Agent::KMS_Agent__FilterOperator) +                i_pSourceQueryParameters->m_aFilterParameters[i].m_eFilterOperator; +    } + +    // copy PreviousPageLastIDValue +    i_pQueryParameters->PreviousPageLastIDValue = +            (utf8cstr) soap_malloc(i_pstSoap, +            sizeof (i_pSourceQueryParameters->m_wsPreviousPageLastIDValue)); +    if (i_pQueryParameters->PreviousPageLastIDValue == NULL) +    { +        return (false); +    } +    strncpy(i_pQueryParameters->PreviousPageLastIDValue, +            i_pSourceQueryParameters->m_wsPreviousPageLastIDValue, +            sizeof (i_pSourceQueryParameters->m_wsPreviousPageLastIDValue)); +    i_pQueryParameters->PreviousPageLastIDValue[sizeof (i_pSourceQueryParameters->m_wsPreviousPageLastIDValue)-1] = '\0'; + +    // copy PreviousPageLastIDValue +    i_pQueryParameters->PreviousPageLastSortFieldValue = +            (utf8cstr) soap_malloc(i_pstSoap, +            sizeof (i_pSourceQueryParameters-> +            m_wsPreviousPageLastSortFieldValue)); +    if (i_pQueryParameters->PreviousPageLastSortFieldValue == NULL) +    { +        return (false); +    } +    strncpy(i_pQueryParameters->PreviousPageLastSortFieldValue, +            i_pSourceQueryParameters->m_wsPreviousPageLastSortFieldValue, +            sizeof (i_pSourceQueryParameters-> +            m_wsPreviousPageLastSortFieldValue)); +    i_pQueryParameters->PreviousPageLastSortFieldValue[sizeof (i_pSourceQueryParameters-> +            m_wsPreviousPageLastSortFieldValue)-1] = 0; + +    return (true); +} + +static void CopyQueryParametersFromResponse ( +                                             struct KMSAgent_QueryParameters *i_pQueryParameters, +                                             struct KMS_Agent::KMS_Agent__QueryParameters *i_pSourceQueryParameters) +{ + +    // copy sort field name +    if (i_pSourceQueryParameters->SortFieldName) +    { +        strncpy(i_pQueryParameters->m_wsSortFieldName, +                i_pSourceQueryParameters->SortFieldName, +                sizeof(i_pQueryParameters->m_wsSortFieldName)); +        i_pQueryParameters->m_wsSortFieldName[sizeof(i_pQueryParameters->m_wsSortFieldName)-1] = '\0'; +    } + +    // copy order +    i_pQueryParameters->m_eSortOrder = +            (KMSAgent_SortOrder) i_pSourceQueryParameters->SortOrder; + +    // copy filter parameters +    i_pQueryParameters->m_iSizeFilterParameters = +            i_pSourceQueryParameters->FilterParameters.__size; + +    // we only accept this amount of parameters +    if (i_pQueryParameters->m_iSizeFilterParameters >= KMS_MAX_AGENT_FILTER_PARAMETERS) +    { +        // this should not happen, but just for defending the code +        i_pQueryParameters->m_iSizeFilterParameters = KMS_MAX_AGENT_FILTER_PARAMETERS; +    } + +    for (int i = 0; i < i_pQueryParameters->m_iSizeFilterParameters; i++) +    { +        struct KMS_Agent::KMS_Agent__FilterParameters *pParameters; + +        pParameters = i_pSourceQueryParameters->FilterParameters.__ptr + i; + +        i_pQueryParameters->m_aFilterParameters[i].m_eFilterOperator +                = (KMSAgent_FilterOperator) pParameters->FilterOperator; + +        if (pParameters->FieldName) +        { +            strncpy(i_pQueryParameters->m_aFilterParameters[i].m_wsFieldName, +                    pParameters->FieldName, +                    sizeof (i_pQueryParameters->m_aFilterParameters[i].m_wsFieldName)); +            i_pQueryParameters-> +                    m_aFilterParameters[i].m_wsFieldName[sizeof (i_pQueryParameters->m_aFilterParameters[i].m_wsFieldName) - 1] = '\0'; +        } + +        if (pParameters->FieldValue) +        { +            strncpy(i_pQueryParameters->m_aFilterParameters[i].m_wsFieldValue, +                    pParameters->FieldValue, +                    sizeof(i_pQueryParameters->m_aFilterParameters[i].m_wsFieldValue)); +            i_pQueryParameters-> +                    m_aFilterParameters[i].m_wsFieldValue[sizeof(i_pQueryParameters->m_aFilterParameters[i].m_wsFieldValue)-1] = '\0'; +        } +    } +    // copy PreviousPageLastIDValue +    if (i_pSourceQueryParameters->PreviousPageLastIDValue) +    { +        strncpy(i_pQueryParameters->m_wsPreviousPageLastIDValue, +                i_pSourceQueryParameters->PreviousPageLastIDValue, +                sizeof(i_pQueryParameters->m_wsPreviousPageLastIDValue)); +        i_pQueryParameters->m_wsPreviousPageLastIDValue[sizeof(i_pQueryParameters->m_wsPreviousPageLastIDValue)-1] = '\0'; +    } + +    // copy PreviousPageLastSortFieldValue +    if (i_pSourceQueryParameters->PreviousPageLastSortFieldValue) +    { +        strncpy(i_pQueryParameters->m_wsPreviousPageLastSortFieldValue, +                i_pSourceQueryParameters->PreviousPageLastSortFieldValue, +                sizeof(i_pQueryParameters->m_wsPreviousPageLastSortFieldValue)); +        i_pQueryParameters->m_wsPreviousPageLastSortFieldValue[sizeof(i_pQueryParameters->m_wsPreviousPageLastSortFieldValue)-1] = '\0'; +    } + +} + +/** + *  copies data unit to the soap data unit structure, placing the xsd_string types on the + *  gsoap heap. + *  @return(false if soap_malloc fails + */ +static bool CopyDataUnitFromRequest (struct soap *i_pstSoap, +                                     struct KMS_Agent::KMS_Agent__DataUnit *i_pDataUnit, +                                     const KMSAgent_DataUnit * const i_pSourceDataUnit) +{ + +    if (i_pSourceDataUnit) +    { +        // copy field name +        i_pDataUnit->DataUnitID = +                (utf8cstr) soap_malloc(i_pstSoap, +                2 * sizeof (i_pSourceDataUnit->m_acDataUnitID) + 1); +        if (i_pDataUnit->DataUnitID == NULL) +        { +            return (false); +        } + +        ConvertBinaryToUTF8HexString(i_pDataUnit->DataUnitID, +                i_pSourceDataUnit->m_acDataUnitID, +                KMS_DATA_UNIT_ID_SIZE); +    } +    else +    { +        strcpy(i_pDataUnit->DataUnitID, ""); +    } + +    i_pDataUnit->ExternalUniqueID = (utf8cstr) soap_malloc(i_pstSoap, +            2 * sizeof (i_pSourceDataUnit->m_acExternalUniqueID) + 1); +    if (i_pDataUnit->ExternalUniqueID == NULL) +    { +        return (false); +    } + +    if (i_pSourceDataUnit->m_iExternalUniqueIDLength > 0 && +        i_pSourceDataUnit->m_iExternalUniqueIDLength <= KMS_MAX_EXTERNAL_UNIQUE_ID_SIZE) +    { +        ConvertBinaryToUTF8HexString(i_pDataUnit->ExternalUniqueID, +                i_pSourceDataUnit->m_acExternalUniqueID, +                i_pSourceDataUnit->m_iExternalUniqueIDLength); +    } +    else +    { +        strcpy(i_pDataUnit->ExternalUniqueID, ""); +    } + +    i_pDataUnit->ExternalTag = (utf8cstr) soap_malloc(i_pstSoap, sizeof (i_pSourceDataUnit->m_acExternalTag)); +    if (i_pDataUnit->ExternalTag == NULL) +    { +        return (false); +    } + +    if (strlen(i_pSourceDataUnit->m_acExternalTag) <= sizeof (i_pSourceDataUnit->m_acExternalTag)) +    { +        strncpy(i_pDataUnit->ExternalTag, +                i_pSourceDataUnit->m_acExternalTag, +                sizeof (i_pSourceDataUnit->m_acExternalTag)); +        i_pDataUnit->ExternalTag[sizeof (i_pSourceDataUnit->m_acExternalTag)-1] = '\0'; +    } +    else +    { +        strcpy(i_pDataUnit->ExternalTag, ""); +    } + +    i_pDataUnit->Description = (utf8cstr) soap_malloc(i_pstSoap, sizeof (i_pSourceDataUnit->m_acDescription)); +    if (i_pDataUnit->Description == NULL) +    { +        return (false); +    } +    if (strlen(i_pSourceDataUnit->m_acDescription) <= sizeof (i_pSourceDataUnit->m_acDescription)) +    { +        strncpy(i_pDataUnit->Description, +                i_pSourceDataUnit->m_acDescription, +                sizeof (i_pSourceDataUnit->m_acDescription)); +        i_pDataUnit->Description[sizeof (i_pSourceDataUnit->m_acDescription)-1] = '\0'; +    } +    else +    { +        strcpy(i_pDataUnit->Description, ""); +    } + +    i_pDataUnit->DataUnitState = (KMS_Agent::KMS_Agent__DataUnitState) i_pSourceDataUnit->m_iDataUnitState; + +    return (true); +} + +/** + *  Converts an ExternalUniqueID value to UTF8Hexstring value from gSoap managed heap storage + *  @param  i_pstSoap pointer to gSoap runtime + *  @param  i_pExternalUniqueID non-NULL pointer to an external unique id to be converted + *  @return(NULL if memory cannot be allocated + */ +static char * ConvertBinaryDataFromRequest (struct soap *i_pstSoap, +                                            const unsigned char * i_pBinaryData, +                                            int i_iBinaryDataLen) +{ +    char * pBinaryData = (char *) soap_malloc(i_pstSoap, 2 * i_iBinaryDataLen + 1); +    if (pBinaryData != NULL) +    { +        ConvertBinaryToUTF8HexString(pBinaryData, +                i_pBinaryData, +                i_iBinaryDataLen); +    } +    return (pBinaryData); +} + +/** + *  Converts a UTF8 char string value to a fixed length array from + *  gSoap managed heap storage + *  @param  pointer to gSoap runtime + *  @param  i_pUTF8string non-NULL pointer to a null terminated UTF8 string + *  @param  i_iLen size of arrray to be allocated + *  @return(NULL if gSoap allocated storage could not be obtained + */ +static char * ConvertUTF8StringFromRequest (struct soap *i_pstSoap, +                                            const char * const i_pUTF8string, +                                            size_t i_iLen) +{ +    char * pUTF8string = NULL; +    pUTF8string = (char *) soap_malloc(i_pstSoap, i_iLen); +    if (pUTF8string != NULL) +    { +        strncpy(pUTF8string, i_pUTF8string, i_iLen); +        pUTF8string[i_iLen-1] = '\0'; +    } +    return (pUTF8string); +} + +static KMSAgent_ArrayOfKeyGroups * CopyKeyGroupsResponse +( + struct KMS_Agent::KMS_Agent__ArrayOfKeyGroups *i_pKeyGroupsResponse + ) +{ +    // alloc memory for result +    KMSAgent_ArrayOfKeyGroups *pResult = +            (KMSAgent_ArrayOfKeyGroups *) calloc(1, sizeof (KMSAgent_ArrayOfKeyGroups)); + +    // no memory, return +    if (pResult == NULL) +    { +        return (NULL); +    } + +    // copy size +    pResult->m_iSize = i_pKeyGroupsResponse->__size; + +    // if the size is 0, return(an empty result +    if (pResult->m_iSize == 0) +    { +        return (pResult); +    } + +    // alloc memory for all key groups +    pResult->m_pKeyGroups = (KMSAgent_KeyGroup*) +            calloc(1, sizeof (KMSAgent_KeyGroup) * pResult->m_iSize); + +    if (pResult->m_pKeyGroups == NULL) +    { +        free(pResult); +        return (NULL); +    } + +    for (int i = 0; i < pResult->m_iSize; i++) +    { +        KMSAgent_KeyGroup *pKeyGroup; + +        pKeyGroup = &(pResult->m_pKeyGroups[i]); + +        strncpy(pKeyGroup->m_acKeyGroupID, +                i_pKeyGroupsResponse->__ptr[i].KeyGroupID, +                sizeof(pKeyGroup->m_acKeyGroupID)); +        pKeyGroup->m_acKeyGroupID[sizeof(pKeyGroup->m_acKeyGroupID)-1] = '\0'; + +        strncpy(pKeyGroup->m_acDescription, +                i_pKeyGroupsResponse->__ptr[i].Description, +                sizeof(pKeyGroup->m_acDescription)); +        pKeyGroup->m_acDescription[sizeof(pKeyGroup->m_acDescription)-1] = '\0'; +    } + +    return (pResult); +} +/** + *  allocate storage for the KMSAgent_ArrayOfKeys struct and the array of keys returned in the + *  soap response. + *  @param  i_pProfile pointer to profile + *  @param  io_pClusterIndex pointer to the cluster index value which is used + *      by AES Key Unwrap to access the KWK for the KMA corresponding to the + *      cluster index. + *  @param  i_pKeysResponse pointer to the soap response' array of keys struct + *  @return(pointer to allocated KMSAgent_ArrayOfKeys and the corresponding keys, returns NULL + *  on any error and frees any allocated storage before returning.  For response data validation errors a + *  message will be logged. + */ +static KMSAgent_ArrayOfKeys * CopyDataUnitKeysResponse ( +                    KMSClientProfile *i_pProfile, +                    int * const io_pClusterIndex, +                    struct KMS_Agent::KMS_Agent__ArrayOfKeys *i_pKeysResponse) +{ +    KMSAgent_ArrayOfKeys * pResult = +            (KMSAgent_ArrayOfKeys *) calloc(1, sizeof (KMSAgent_ArrayOfKeys)); + +    if (pResult == NULL) +    { +        return (NULL); +    } + +    // if the size is 0, return(an empty result +    if (i_pKeysResponse->__size == 0) +    { +        return (pResult); +    } + +    if (i_pKeysResponse->__size > KMS_MAX_PAGE_SIZE) +    { +        free(pResult); +        LogError(i_pProfile, +                AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEY_ARRAY_SIZE_RESPONSE, +                NULL, +                NULL, +                NULL); +        return (NULL); +    } + +    pResult->m_iSize = i_pKeysResponse->__size; + +    // alloc memory for all keys returned +    pResult->m_pKeys = (KMSAgent_Key*) +            calloc(1, sizeof (KMSAgent_Key) * i_pKeysResponse->__size); + +    if (pResult->m_pKeys == NULL) +    { +        free(pResult); +        return (NULL); +        // no memory, don't log +    } + +    // copy keys from response +    for (int i = 0; i < i_pKeysResponse->__size; i++) +    { +        if (KMS_KEY_ID_SIZE != ConvertUTF8HexStringToBinary( +            i_pKeysResponse->__ptr[i].KeyID, NULL)) +        { +            free(pResult->m_pKeys); +            free(pResult); + +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEY_RESPONSE, +                    NULL, +                    NULL, +                    NULL); +            return (NULL); +        } + +        ConvertUTF8HexStringToBinary( +                i_pKeysResponse->__ptr[i].KeyID, pResult->m_pKeys[i].m_acKeyID); + +        if ((KMS_AGENT_KEY_STATE) i_pKeysResponse->__ptr[i].KeyState < KMS_KEY_STATE_ACTIVE_PROTECT_AND_PROCESS || +            (KMS_AGENT_KEY_STATE) i_pKeysResponse->__ptr[i].KeyState > KMS_KEY_STATE_COMPROMISED) +        { +            free(pResult->m_pKeys); +            free(pResult); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEY_STATE_RESPONSE, +                    NULL, +                    NULL, +                    NULL); +            return (NULL); +        } +        pResult->m_pKeys[i].m_iKeyState = (KMS_AGENT_KEY_STATE) i_pKeysResponse->__ptr[i].KeyState; + +        if ((KMS_KEY_TYPE) i_pKeysResponse->__ptr[i].KeyType != (KMS_KEY_TYPE)KMS_KEY_TYPE_AES_256) +        { +            free(pResult->m_pKeys); +            free(pResult); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEY_TYPE_RESPONSE, +                    NULL, +                    NULL, +                    NULL); +            return (NULL); +        } +        pResult->m_pKeys[i].m_iKeyType = (KMS_KEY_TYPE) i_pKeysResponse->__ptr[i].KeyType; + +        strncpy(pResult->m_pKeys[i].m_acKeyGroupID, +                i_pKeysResponse->__ptr[i].KeyGroupID, +                sizeof(pResult->m_pKeys[i].m_acKeyGroupID)); +        pResult->m_pKeys[i].m_acKeyGroupID[sizeof(pResult->m_pKeys[i].m_acKeyGroupID)-1] = '\0'; + +        CAgentLoadBalancer *pAgentLoadBalancer = reinterpret_cast +                <CAgentLoadBalancer *> (i_pProfile->m_pAgentLoadBalancer); + +        if (pAgentLoadBalancer->AESKeyWrapSupported(*io_pClusterIndex)) +        { +            if (i_pKeysResponse->__ptr[i].Key.__size != KMS_MAX_WRAPPED_KEY_SIZE) +            { +                free(pResult->m_pKeys); +                free(pResult); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_WRAPPED_KEY_LENGTH_RESPONSE, +                        NULL, +                        NULL, +                        NULL); +                return (NULL); +            } +            else +            { +                if (pAgentLoadBalancer->AESKeyUnwrap(io_pClusterIndex, +                    i_pKeysResponse->__ptr[i].Key.__ptr, +                    pResult->m_pKeys[i].m_acKey) == false) +                { +                    free(pResult->m_pKeys); +                    free(pResult); +                    LogError(i_pProfile, +                            AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_AESKEYUNWRAP_ERROR, +                            NULL, +                            NULL, +                            NULL); + +                    return (NULL); +                } +            } +        } +        else  // non-AES Key Wrap +        { +            if (i_pKeysResponse->__ptr[i].Key.__size != KMS_MAX_KEY_SIZE) +            { +                free(pResult->m_pKeys); +                free(pResult); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEY_LENGTH_RESPONSE, +                        NULL, +                        NULL, +                        NULL); +                return (NULL); +            } + +            memcpy(pResult->m_pKeys[i].m_acKey, +                    i_pKeysResponse->__ptr[i].Key.__ptr, +                    KMS_MAX_KEY_SIZE); +        } + +        pResult->m_pKeys[i].m_iKeyLength = KMS_MAX_KEY_SIZE; + +        if (KMSAgentKeyCallout(pResult->m_pKeys[i].m_acKey) != 0) +        { +            free(pResult->m_pKeys); +            free(pResult); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_KEY_CALLOUT_ERROR, +                    NULL, +                    NULL, +                    NULL); +            return (NULL); +        } +    } + +    return (pResult); +} + +/** + *  This function returns the API status code based upon the error string in the profile and + *  availability of KMAs. KMA availability determination is based upon the i_iKMAFailoverReturnCode + *  parameter and the size of the cluster.  A cluster size of 0 is an indicator that there are + *  no KMAs available, unless cluster discovery is disabled by the profile's cluster discovery + *  frequency. + * + *  @param i_pProfile  pointer to the profile + *  @param i_iKMAFailoverReturnCode the return(code from CAgentLoadBalancer::Failover() or 0 + *  if it was not called.  This is used to for determining if KMS_AGENT_STATUS_KMS_UNAVAILABLE + *  needs to be returned. + *  @returns KMS_AGENT_STATUS_GENERIC_ERROR + *  unless the profile's last error message field contains a message substring matching one of the + *  KMSAgent service soap fault strings. + * + */ +static KMS_AGENT_STATUS KMSAgent_GetLastStatusCode (KMSClientProfile *i_pProfile, +                                                    int i_iKMAFailoverReturnCode) +{ +    bool bServerError = false; + +    FATAL_ASSERT(i_pProfile); + +    // see KMSAgentLoadBalancer.h for return codes from Failover + +    if (i_iKMAFailoverReturnCode == CAgentLoadBalancer::NO_FIPS_KMA_AVAILABLE) +    { +        return (KMS_AGENT_STATUS_NO_FIPS_KMAS_AVAILABLE); +    } + +    // parse for server errors - +    // when KMAs have no ready keys we want to inform the client, vs reporting that the KMS is unavailable +    bServerError = ServerError(i_pProfile->m_wsErrorString, 0); + +    // parse for Soap errors +    const char* sFaultstringStart = strstr(i_pProfile->m_wsErrorString, "SoapFaultString="); + +    int iErrorCode = INVALID_CLIENT_ERROR; // initially + + +    // if there is a Soap error +    if (sFaultstringStart) +    { +        if (SSL_InvalidCertificate(sFaultstringStart)) +        { +            // this can be caused by the KMS invalidating the agent's cert +            return (KMS_AGENT_STATUS_ACCESS_DENIED); +        } +        iErrorCode = GET_FAULT_CODE(sFaultstringStart + strlen("SoapFaultString=")); +    } + + +#ifdef METAWARE +    // log the failure code/cause to the event log +    LogToFile(i_iKMAFailoverReturnCode, i_pProfile->m_wsErrorString); +    LogToFile(iErrorCode, "error code"); +#endif + + +    // parse return code passed in from last call to FailOver, Balance or BalanceByDataUnitKeyID +    // if failover reported no kma and there is a valid server error and client couldn't get keys +    if (i_iKMAFailoverReturnCode == CAgentLoadBalancer::NO_KMA_AVAILABLE && +        bServerError && +        iErrorCode == CLIENT_ERROR_AGENT_NO_READY_KEYS) +    { +        return (KMS_AGENT_STATUS_KMS_UNAVAILABLE); +    } + +    // if there is a server error and we are doing discovery +    if (bServerError && +        ((i_pProfile->m_iClusterDiscoveryFrequency > 0 && +        i_pProfile->m_iClusterNum == 0) +        || iErrorCode == CLIENT_ERROR_AGENT_APPLIANCE_LOCKED)) +    { +        return (KMS_AGENT_STATUS_KMS_UNAVAILABLE); +    } + +    if (bServerError && i_iKMAFailoverReturnCode == CAgentLoadBalancer::NO_KMA_AVAILABLE) +    { +        return (KMS_AGENT_STATUS_KMS_UNAVAILABLE); +    } + +    if ( i_iKMAFailoverReturnCode == CAgentLoadBalancer::AES_KEY_UNWRAP_ERROR ) +        return (KMS_AGENT_AES_KEY_UNWRAP_ERROR); +    if ( i_iKMAFailoverReturnCode == CAgentLoadBalancer::AES_KEY_WRAP_SETUP_ERROR ) +        return (KMS_AGENT_AES_KEY_WRAP_SETUP_ERROR); + +    if (iErrorCode == CLIENT_ERROR_ACCESS_DENIED) +        return (KMS_AGENT_STATUS_ACCESS_DENIED); +    if (iErrorCode == CLIENT_ERROR_SERVER_BUSY) +        return (KMS_AGENT_STATUS_SERVER_BUSY); +    if (iErrorCode == CLIENT_ERROR_AGENT_INVALID_PARAMETERS) +        return (KMS_AGENT_STATUS_INVALID_PARAMETER); +    if (iErrorCode == CLIENT_ERROR_AGENT_KEY_DOES_NOT_EXIST) +        return (KMS_AGENT_STATUS_KEY_DOES_NOT_EXIST); +    if (iErrorCode == CLIENT_ERROR_AGENT_KEY_DESTROYED) +        return (KMS_AGENT_STATUS_KEY_DESTROYED); +    if (iErrorCode == CLIENT_ERROR_AGENT_DATA_UNIT_ID_NOT_FOUND_EXTERNAL_ID_EXISTS) +        return (KMS_AGENT_STATUS_DATA_UNIT_ID_NOT_FOUND_EXTERNAL_ID_EXISTS); +    if (iErrorCode == CLIENT_ERROR_AGENT_DUPLICATE_EXTERNAL_ID) +        return (KMS_AGENT_STATUS_EXTERNAL_UNIQUE_ID_EXISTS); +    if (iErrorCode == CLIENT_ERROR_AGENT_NO_READY_KEYS) +        return (KMS_AGENT_STATUS_KMS_NO_READY_KEYS); + +    // this check is made last to allow other specific errors that may have occurred to take precedence, +    // e.g. return access denied before reporting No FIPS KMAs +    if (i_pProfile->m_eKMSmode == FIPS_MODE && +        KMSClient_NoFIPSCompatibleKMAs(i_pProfile)) +    { +        return (KMS_AGENT_STATUS_NO_FIPS_KMAS_AVAILABLE); +    } + +    return (KMS_AGENT_STATUS_GENERIC_ERROR); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_InitializeLibrary + *--------------------------------------------------------------------------*/ +#include "KMSAuditLogger.h" + +extern "C" +KMS_AGENT_STATUS KMSAgent_InitializeLibrary (utf8cstr const i_pWorkingDirectory, +                                             int i_bUseFileLog) + +{ +    bool bSuccess; + +#if defined(METAWARE) +#warn "debug timing is on" +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_InitializeLibrary); +#endif + +#if defined(DEBUG) && defined(METAWARE) +    log_printf("KMSAgent_InitializeLibrary : Entered"); +#endif + +    bSuccess = KMSClient_InitializeLibrary( +            i_pWorkingDirectory, +            i_bUseFileLog); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMS_AGENT_STATUS_GENERIC_ERROR); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_KnownAnswerTests + * + *--------------------------------------------------------------------------*/ +KMS_AGENT_STATUS KMSAgent_KnownAnswerTests() +{ +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_KnownAnswerTests); +#endif + +   // Known Answer Test on AES Key Wrap code +   if ( KnownAnswerTestAESKeyWrap() != 0 ) +   { +       RETURN(KMS_AGENT_STATUS_FIPS_KAT_AES_KEYWRAP_ERROR); +   } + +   if ( KnownAnswerTestAESECB() != 0 ) +   { +       RETURN(KMS_AGENT_STATUS_FIPS_KAT_AES_ECB_ERROR); +   } + +   if ( KnownAnswerTestHMACSHA1() != 0 ) +   { +       RETURN(KMS_AGENT_STATUS_FIPS_KAT_HMAC_SHA1_ERROR); +   } + +   RETURN(KMS_AGENT_STATUS_OK); + +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_FinalizeLibrary + * + *--------------------------------------------------------------------------*/ + +extern "C" +KMS_AGENT_STATUS KMSAgent_FinalizeLibrary () +{ +    bool bSuccess; + +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_FinalizeLibrary); +#endif + +    bSuccess = KMSClient_FinalizeLibrary(); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMS_AGENT_STATUS_GENERIC_ERROR); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_GetLastErrorMessage + * + *--------------------------------------------------------------------------*/ + +extern "C" +utf8cstr KMSAgent_GetLastErrorMessage (KMSClientProfile* i_pProfile) +{ +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_GetLastErrorMessage); +#endif + +    if (i_pProfile == NULL) +    { +        RETURN(NULL); +    } + +    RETURN(KMSClient_GetLastErrorMessage(i_pProfile)); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_GetClusterInformation + * + *--------------------------------------------------------------------------*/ +extern "C" +KMS_AGENT_STATUS KMSAgent_GetClusterInformation ( +                                                 KMSClientProfile * const i_pProfile, +                                                 int i_iEntitySiteIDSize, +                                                 int i_iClusterEntryArraySize, +                                                 utf8cstr const o_pEntitySiteID, +                                                 int * const o_pApplianceNum, +                                                 KMSClusterEntry * const o_pClusterEntryArray) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_GetClusterInformation); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!o_pEntitySiteID || (i_iEntitySiteIDSize <= (KMS_MAX_ENTITY_SITE_ID))) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "EntitySiteIDSize arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_iClusterEntryArraySize > KMS_MAX_CLUSTER_NUM) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "i_iClusterEntryArraySize exceeds KMS_MAX_CLUSTER_NUM"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +     +    if (!o_pApplianceNum) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ApplianceNum arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!o_pClusterEntryArray || +        (i_iClusterEntryArraySize <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ClusterEntry or Size arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    bSuccess = KMSClient_GetClusterInformation( +            i_pProfile, +            o_pEntitySiteID, +            i_iEntitySiteIDSize, +            o_pApplianceNum, +            o_pClusterEntryArray, +            i_iClusterEntryArraySize); + +    // KMSClient_GetClusterInformation logs if there was an error + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, 0)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_SelectAppliance ( +                                           KMSClientProfile * const i_pProfile, +                                           utf8cstr const i_pApplianceAddress) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_SelectAppliance); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_SELECT_APPLIANCE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pApplianceAddress) +    { +        Log(AUDIT_CLIENT_AGENT_GET_CLUSTER_INFORMATION_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ApplianceAddress arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    // All modes are supported by this function. + +    bSuccess = KMSClient_SelectAppliance(i_pProfile, i_pApplianceAddress); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, 0)); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_LoadProfile + * + *--------------------------------------------------------------------------*/ +extern "C" +KMS_AGENT_STATUS KMSAgent_LoadProfile ( +                                       KMSClientProfile * const io_pProfile, +                                       utf8cstr const i_pProfileName, +                                       utf8cstr const i_pAgentID, +                                       utf8cstr const i_pPassphrase, +                                       utf8cstr const i_pInitialApplianceAddress, +                                       int i_iTransactionTimeout, +                                       int i_iFailOverLimit, +                                       int i_iClusterDiscoveryFrequency, +                                       int i_eKMSmode) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_LoadProfile); +#endif + +#if defined(DEBUG) && defined(METAWARE) +    log_printf("KMSAgent_LoadProfile : Entered"); +#endif +    if (!io_pProfile || +        !i_pProfileName || (strlen(i_pProfileName) <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile or Name arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pInitialApplianceAddress || (strlen(i_pInitialApplianceAddress) <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "InitialApplianceAddress arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_iTransactionTimeout <= 0) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "TransactionTimeout arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (i_iClusterDiscoveryFrequency < 0) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ClusterDiscoveryFrequency arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    // for enrollment both arguments are required +    if ((i_pAgentID && !i_pPassphrase) || (i_pPassphrase && !i_pAgentID)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Enrollment requires AgentID & Passphrase"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pAgentID && (strlen(i_pAgentID) <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "AgentID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pPassphrase && (strlen(i_pPassphrase) <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Passphrase arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if ( i_eKMSmode != DEFAULT_MODE && i_eKMSmode != FIPS_MODE ) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "KMS security mode arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (KMSClient_ProfileLoaded(io_pProfile)) +    { +        Log(AUDIT_CLIENT_AGENT_LOAD_PROFILE_PROFILE_ALREADY_LOADED, +                NULL, +                NULL, +                "profile is already loaded and should be unloaded first"); +        RETURN(KMS_AGENT_STATUS_PROFILE_ALREADY_LOADED); +    } + +    memset(io_pProfile, 0, sizeof (KMSClientProfile)); +    char sInitialApplianceAddress[KMS_MAX_NETWORK_ADDRESS+1]; +    strncpy(sInitialApplianceAddress, i_pInitialApplianceAddress, sizeof(sInitialApplianceAddress)); +    sInitialApplianceAddress[sizeof(sInitialApplianceAddress)-1] = '\0'; +     +    // Convert to lower case + +    for ( size_t i = 0; i < strlen( sInitialApplianceAddress ); i++ ) +    { +        if ( isupper( sInitialApplianceAddress[i] ) ) +        { +            sInitialApplianceAddress[i] = tolower( sInitialApplianceAddress[i] ); +        } +    } + +    bSuccess = KMSClient_LoadProfile( +                            io_pProfile, +                            i_pProfileName, +                            i_pAgentID, +                            i_pPassphrase, +                            sInitialApplianceAddress, +                            i_iTransactionTimeout, +                            i_iFailOverLimit, +                            i_iClusterDiscoveryFrequency, +                            i_eKMSmode); + +    if (bSuccess) +    { +#if defined(DEBUG) && defined(METAWARE) +        log_printf("KMSAgent_LoadProfile : Returned ok"); +#endif +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    // when not enrolling & cluster discovery is disabled there are no +    // soap transactions so failover would not have occurred +    bool bEnrolling = i_pAgentID && i_pPassphrase; + +    if (!bEnrolling && +        i_iClusterDiscoveryFrequency == 0) +    { +        RETURN(KMSAgent_GetLastStatusCode(io_pProfile, 0)); +    } +    else +    { +//        if (i_eKMSmode == FIPS_MODE && +//            KMSClient_NoFIPSCompatibleKMAs(io_pProfile)) +//        { +//            RETURN(KMSAgent_GetLastStatusCode(io_pProfile, +//                CAgentLoadBalancer::NO_FIPS_KMA_AVAILABLE)); +//        } + +        RETURN(KMSAgent_GetLastStatusCode(io_pProfile, +            CAgentLoadBalancer::NO_KMA_AVAILABLE)); +    } +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_UnloadProfile + * + *--------------------------------------------------------------------------*/ +extern "C" +KMS_AGENT_STATUS KMSAgent_UnloadProfile (KMSClientProfile * const i_pProfile) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_UnloadProfile); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_UNLOAD_PROFILE_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    bSuccess = KMSClient_UnloadProfile(i_pProfile); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, 0)); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_DeleteProfile + * + *--------------------------------------------------------------------------*/ +extern "C" +KMS_AGENT_STATUS KMSAgent_DeleteProfile (utf8cstr i_pProfileName) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_DeleteProfile); +#endif + +    if (!i_pProfileName || (strlen(i_pProfileName) <= 0)) +    { +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    bSuccess = KMSClient_DeleteProfile(i_pProfileName); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMS_AGENT_STATUS_GENERIC_ERROR); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_ListKeyGroups + * + *--------------------------------------------------------------------------*/ + +extern "C" +KMS_AGENT_STATUS KMSAgent_ListKeyGroups ( +                                         KMSClientProfile * const i_pProfile, +                                         KMSAgent_ArrayOfKeyGroups* * const o_ppKeyGroups) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_ListKeyGroups); +#endif + +    int bIsLastPage; +    struct KMSAgent_QueryParameters stQueryParameters; + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_LIST_KEY_GROUPS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_ppKeyGroups) +    { +        Log(AUDIT_CLIENT_AGENT_LIST_KEY_GROUPS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "KeyGroups arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; + +    // Get Key Groups +    memset(&stQueryParameters, 0, sizeof (stQueryParameters)); + +    struct KMS_Agent::KMS_Agent__QueryParameters oQueryParameters; +    struct KMS_Agent::KMS_Agent__ListKeyGroupsResponse oResponse; + +    memset(&oQueryParameters, 0, sizeof (oQueryParameters)); + +    bSuccess = CopyQueryParametersFromRequest(pstSoap, +            KMS_MAX_LIST_KEY_GROUPS, +            &oQueryParameters, +            &stQueryParameters); +    if (!bSuccess) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory, don't log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; + +    int iIndex = pLoadBalancer->Balance(); + +    if ( iIndex >= 0 ) +    { +        do +        { +            const char* sURL = +                    pLoadBalancer->GetHTTPSURL(iIndex, i_pProfile->m_iPortForAgentService); +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent::soap_call_KMS_Agent__ListKeyGroups( +                    pstSoap, +                    sURL, +                    NULL, +                    oQueryParameters, +                    oResponse) == SOAP_OK; + +            if (!bSuccess) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, AUDIT_CLIENT_AGENT_LIST_KEY_GROUPS_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        bIsLastPage = oResponse.LastPage; + +        *o_ppKeyGroups = CopyKeyGroupsResponse(&oResponse.KeyGroups); +        if (*o_ppKeyGroups == NULL) +        { +            bSuccess = false; +            // no memory, don't log +        } + +        CopyQueryParametersFromResponse(&stQueryParameters, +                &oResponse.NextPageQueryParameters); +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +        RETURN(KMS_AGENT_STATUS_OK); + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_FreeArrayOfKeyGroups + * + *--------------------------------------------------------------------------*/ + +extern "C" +void KMSAgent_FreeArrayOfKeyGroups ( +                                    struct KMSAgent_ArrayOfKeyGroups *i_pArrayOfKeyGroups) +{ +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_FreeArrayOfKeyGroups); +#endif +    if (!i_pArrayOfKeyGroups) +    { +        return; +    } + +    // free memory for all information groups +    if (i_pArrayOfKeyGroups->m_pKeyGroups) +    { +        free(i_pArrayOfKeyGroups->m_pKeyGroups); +    } + +    free(i_pArrayOfKeyGroups); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_CreateKey ( +                                     KMSClientProfile * const i_pProfile, +                                     const KMSAgent_DataUnit * const i_pDataUnit, +                                     KEY_GROUP_ID const i_pKeyGroupID, +                                     KMSAgent_Key * const o_pKey) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_CreateKey); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pKey) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Key arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    if (i_pKeyGroupID && +        strlen(i_pKeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "GroupID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    struct KMS_Agent::KMS_Agent__DataUnit +                        stDataUnit = {"", "", "", "", +                            (KMS_Agent::KMS_Agent__DataUnitState) 0}; + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__CreateKeyResponse oResponse; + +    if (i_pDataUnit != NULL) +    { +        if (!CopyDataUnitFromRequest(pstSoap, +            &stDataUnit, +            i_pDataUnit)) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pKeyGroupID = NULL; +    if (i_pKeyGroupID) +    { +        pKeyGroupID = ConvertUTF8StringFromRequest(pstSoap, +                i_pKeyGroupID, +                KMS_MAX_KEY_GROUP_ID_SIZE + 1); +        if (pKeyGroupID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; + +    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +    int iIndex; +    UTF8_KEYID acKWKID; +    bool bClientAESKeyWrapSetupError = false; + +    if (i_pDataUnit) +    { +        // attempt to maintain affinity with KMA for specified DU ID +        iIndex = pLoadBalancer->BalanceByDataUnitID( +                i_pDataUnit->m_acDataUnitID, +                KMS_DATA_UNIT_ID_SIZE); +    } +    else +    { +        iIndex = pLoadBalancer->Balance(); +    } +     +    if (iIndex >= 0) +    { +        do +        { +            bSuccess = true; +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            Long64 lKMAID = pLoadBalancer->GetKMAID(iIndex); + +            if (bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +            { +                // if this fails we want to utilize normal failover logic, GetKWKID +                // logs error +                bSuccess = pLoadBalancer->GetKWKID(iIndex, lKMAID, pstSoap, +					acKWKID, &bClientAESKeyWrapSetupError) ? true : false; +                if (bSuccess) +                { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__CreateKey2( +                            pstSoap, +                            sURL, +                            NULL, +                            stDataUnit, +                            i_pKeyGroupID ? pKeyGroupID : (char *) "", +                            acKWKID, +                            //NOTE: this is ugly but the soap response struct's are the same for both flavors of CreateKey +                            *(reinterpret_cast<struct KMS_Agent::KMS_Agent__CreateKey2Response *>(&oResponse))) == SOAP_OK; +                } +            } +            else  if (bSuccess) // NO AES Key Wrap +            { +                bSuccess = KMS_Agent::soap_call_KMS_Agent__CreateKey( +                        pstSoap, +                        sURL, +                        NULL, +                        stDataUnit, +                        i_pKeyGroupID ? pKeyGroupID : (char *) "", +                        oResponse) == SOAP_OK; +            } + +            // don'f failover for Client side AES Key Wrap setup problems +            if (!bSuccess && !bClientAESKeyWrapSetupError) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_CREATE_KEY_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            if (bSuccess) +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess) && (!bClientAESKeyWrapSetupError)); +    } +    else +    { +        bSuccess = false; +    } + + +#if defined(DEBUG) && defined(METAWARE) +    log_printf("CreateKey gets keyID %s (size %x) \n", +            oResponse.Key.KeyID, +            sizeof (oResponse.Key.KeyID)); +#endif + + +    if (bSuccess) +    { +        if (KMS_KEY_ID_SIZE != ConvertUTF8HexStringToBinary( +            oResponse.Key.KeyID, NULL)) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_KEYID_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        ConvertUTF8HexStringToBinary( +                oResponse.Key.KeyID, // in +                o_pKey->m_acKeyID); // out + +#if defined(DEBUG) && defined(METAWARE) +        log_printf("CreateKey gets keyState %x (size %x) \n", +                oResponse.Key.KeyState, +                sizeof (oResponse.Key.KeyState)); +#endif + +        if ((KMS_AGENT_KEY_STATE) oResponse.Key.KeyState < KMS_KEY_STATE_ACTIVE_PROTECT_AND_PROCESS || +            (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState > KMS_KEY_STATE_COMPROMISED) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_KEY_STATE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        o_pKey->m_iKeyState = (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState; + +#if defined(DEBUG) && defined(METAWARE) +        log_printf("CreateKey o_pKey->m_iKeyState %x (size %x) = " +                "(KMS_AGENT_KEY_STATE) oResponse.Key.KeyState %x (size %x)\n", +                o_pKey->m_iKeyState, +                sizeof (o_pKey->m_iKeyState), +                oResponse.Key.KeyState, +                sizeof (oResponse.Key.KeyState)); +#endif + + +        if ((KMS_KEY_TYPE) oResponse.Key.KeyType != KMS_KEY_TYPE_AES_256) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_KEY_TYPE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +        o_pKey->m_iKeyType = (KMS_KEY_TYPE) oResponse.Key.KeyType; + +        if (strlen(oResponse.Key.KeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_KEY_GROUP_ID_LENGTH_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pKey->m_acKeyGroupID, +                    oResponse.Key.KeyGroupID, +                    sizeof(o_pKey->m_acKeyGroupID)); +            o_pKey->m_acKeyGroupID[sizeof(o_pKey->m_acKeyGroupID)-1] = '\0'; +        } + +        if ( bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +        { +            // verify KWK ID matches what was registered +            if (oResponse.Key.Key.__size != KMS_MAX_WRAPPED_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_WRAPPED_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                if (pLoadBalancer->AESKeyUnwrap(&iIndex, oResponse.Key.Key.__ptr, +                    o_pKey->m_acKey) == false) +                { +                    GetPeerNetworkAddress(sKmaAddress, pstSoap); +                    LogError(i_pProfile, +                            AUDIT_CLIENT_AGENT_CREATE_KEY_AESKEYUNWRAP_ERROR, +                            NULL, +                            sKmaAddress, +                            NULL); + +                    bSuccess = false; +                } +            } +        } +        else if (bSuccess) // non-AES key wrap +        { +            if (oResponse.Key.Key.__size != KMS_MAX_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_CREATE_KEY_INVALID_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                memcpy(o_pKey->m_acKey, +                        oResponse.Key.Key.__ptr, +                        KMS_MAX_KEY_SIZE); +            } +        } + +        if (bSuccess) +        { +            o_pKey->m_iKeyLength = KMS_MAX_KEY_SIZE; + +            if (KMSAgentKeyCallout(o_pKey->m_acKey) != 0) +            { +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_CREATE_KEY_KEY_CALLOUT_ERROR, +                        NULL, +                        NULL, +                        NULL); +                bSuccess = false; +            } +        } +    } + +    if (bSuccess) +    { +        // add Key ID and the creating KMA IP address to the DU cache +        CDataUnitCache* pDataUnitCache = (CDataUnitCache*) i_pProfile->m_pDataUnitCache; + +        if (i_pProfile->m_iClusterDiscoveryFrequency != 0) // load balancing enabled +        { +            bSuccess = pDataUnitCache->Insert( +                    NULL, +                    0, +                    o_pKey->m_acKeyID, +                    KMS_KEY_ID_SIZE, +                    pLoadBalancer->GetApplianceNetworkAddress(iIndex)); +        } +    } +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, +            bClientAESKeyWrapSetupError ? +                CAgentLoadBalancer::AES_KEY_WRAP_SETUP_ERROR : iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_CreateDataUnit ( +                                          KMSClientProfile * const i_pProfile, +                                          const unsigned char * i_pExternalUniqueID, +                                          int i_iExternalUniqueIDIDLen, +                                          utf8cstr const i_pExternalTag, +                                          utf8cstr const i_pDescription, +                                          KMSAgent_DataUnit * const o_pDataUnit) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_CreateDataUnit); +#endif + +#if defined(DEBUG) && defined(METAWARE) +#warn "debug Create Data Unit is on" +    log_printf("KMSAgent_CreateDataUnit entered\n"); +    log_printf("KMSAgent_CreateDataUnit profile=%x\n", i_pProfile); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    // validate input parms + +    if (i_pExternalUniqueID && +        (i_iExternalUniqueIDIDLen <= 0 || +        i_iExternalUniqueIDIDLen > KMS_MAX_EXTERNAL_UNIQUE_ID_SIZE)) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalUniqueID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pExternalTag && strlen(i_pExternalTag) > KMS_MAX_EXTERNAL_TAG) +    { +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pDescription && strlen(i_pDescription) > KMS_MAX_DESCRIPTION) +    { +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__CreateDataUnitResponse oResponse; + +    char * pExternalUniqueID = NULL; +    if (i_pExternalUniqueID) +    { +        pExternalUniqueID = ConvertBinaryDataFromRequest(pstSoap, +                i_pExternalUniqueID, +                i_iExternalUniqueIDIDLen); +        if (pExternalUniqueID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pExternalTag = NULL; +    if (i_pExternalTag) +    { +        pExternalTag = ConvertUTF8StringFromRequest(pstSoap, +                i_pExternalTag, +                strlen(i_pExternalTag) + 1); +        if (pExternalTag == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pDescription = NULL; +    if (i_pDescription) +    { +        pDescription = ConvertUTF8StringFromRequest(pstSoap, +                i_pDescription, +                strlen(i_pDescription) + 1); +        if (pDescription == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->Balance(); + +    if (iIndex >= 0) +    { +        do +        { +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent::soap_call_KMS_Agent__CreateDataUnit( +                    pstSoap, +                    sURL, +                    NULL, +                    i_pExternalUniqueID ? pExternalUniqueID : (char *) "", +                    i_pExternalTag ? pExternalTag : (char *) "", +                    i_pDescription ? pDescription : (char *) "", +                    oResponse) == SOAP_OK; + +            if (!bSuccess) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } + +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        int iDataUnitIDLength; +        iDataUnitIDLength = ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.DataUnitID, o_pDataUnit->m_acDataUnitID); + +        if (iDataUnitIDLength != KMS_DATA_UNIT_ID_SIZE) +        { +#if defined(DEBUG) && defined(METAWARE) +            log_printf("iDataUnitIDLength (%x) != KMS_DATA_UNIT_ID_SIZE (%x)", +                    iDataUnitIDLength, +                    KMS_DATA_UNIT_ID_SIZE); +#endif +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_RESPONSE_INVALID_DU_ID_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        o_pDataUnit->m_iExternalUniqueIDLength = ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.ExternalUniqueID, o_pDataUnit->m_acExternalUniqueID); + +        if (strlen(oResponse.DataUnit.ExternalTag) > KMS_MAX_EXTERNAL_TAG) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_RESPONSE_INVALID_EXTERNAL_TAG_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pDataUnit->m_acExternalTag, +                    oResponse.DataUnit.ExternalTag, +                    sizeof(o_pDataUnit->m_acExternalTag)); +            o_pDataUnit->m_acExternalTag[sizeof(o_pDataUnit->m_acExternalTag)-1] = '\0'; +        } + +        if (strlen(oResponse.DataUnit.Description) > KMS_MAX_DESCRIPTION) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_CREATE_DATA_UNIT_RESPONSE_INVALID_DESCRIPTION_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strcpy(o_pDataUnit->m_acDescription, +                    oResponse.DataUnit.Description); +        } + +        o_pDataUnit->m_iDataUnitState = +                (KMS_AGENT_DATA_UNIT_STATE) oResponse.DataUnit.DataUnitState; +    } + +    if (bSuccess) +    { +        // add data unit ID and the creating KMA IP address to the DU cache +        CDataUnitCache* pDataUnitCache = (CDataUnitCache*) i_pProfile->m_pDataUnitCache; + +        if (i_pProfile->m_iClusterDiscoveryFrequency != 0) // load balancing enabled +        { +            bSuccess = pDataUnitCache->Insert( +                    o_pDataUnit->m_acDataUnitID, +                    KMS_DATA_UNIT_ID_SIZE, +                    NULL, 0, +                    pLoadBalancer->GetApplianceNetworkAddress(iIndex)); +        } +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_DisassociateDataUnitKeys ( +                                                    KMSClientProfile * const i_pProfile, +                                                    const KMSAgent_DataUnit * const i_pDataUnit) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_DisassociateDataUnitKeys); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_DISASSOCIATE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!i_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_DISASSOCIATE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    struct KMS_Agent::KMS_Agent__DataUnit stDataUnit = {"", "", "", "", +        (KMS_Agent::KMS_Agent__DataUnitState) 0}; + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__DisassociateDataUnitKeysResponse oResponse; + +    if (!CopyDataUnitFromRequest(pstSoap, +        &stDataUnit, +        i_pDataUnit)) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory dont' log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->BalanceByDataUnitID( +            i_pDataUnit->m_acDataUnitID, +            KMS_DATA_UNIT_ID_SIZE); + +    if (iIndex >= 0) +    { +        do +        { +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent::soap_call_KMS_Agent__DisassociateDataUnitKeys( +                    pstSoap, +                    sURL, +                    NULL, +                    stDataUnit, +                    oResponse) == SOAP_OK; + +            if (!bSuccess) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_DISASSOCIATE_DATA_UNIT_KEYS_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    // no response data for this transaction + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_RetrieveKey ( +                                       KMSClientProfile * const i_pProfile, +                                       const unsigned char * const i_pKeyID, +                                       const KMSAgent_DataUnit * const i_pDataUnit, +                                       utf8cstr const i_pKeyGroupID, +                                       KMSAgent_Key * const o_pKey) +{ +    bool bSuccess; + +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_RetrieveKey); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pKeyID) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "KeyID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pKey) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Key arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    if (i_pKeyGroupID && +        strlen(i_pKeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "GroupID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    struct KMS_Agent::KMS_Agent__DataUnit stDataUnit = {"", "", "", "", +        (KMS_Agent::KMS_Agent__DataUnitState) 0}; + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__RetrieveKeyResponse oResponse; + +    char * pKeyID = NULL; +    pKeyID = ConvertBinaryDataFromRequest(pstSoap, +            i_pKeyID, +            KMS_KEY_ID_SIZE); +    if (pKeyID == NULL) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory dont' log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    if (i_pDataUnit != NULL) +    { +        if (!CopyDataUnitFromRequest(pstSoap, +            &stDataUnit, +            i_pDataUnit)) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pKeyGroupID = NULL; +    if (i_pKeyGroupID) +    { +        pKeyGroupID = ConvertUTF8StringFromRequest(pstSoap, +                i_pKeyGroupID, +                KMS_MAX_KEY_GROUP_ID_SIZE + 1); +        if (pKeyGroupID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    UTF8_KEYID acKWKID; + +    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; +    bool bClientAESKeyWrapSetupError = false; + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->BalanceByDataUnitKeyID(i_pKeyID, KMS_KEY_ID_SIZE); + +    if (iIndex >= 0) +    { +        do +        { +            bSuccess = true; +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            Long64 lKMAID = pLoadBalancer->GetKMAID(iIndex); + +            if (bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +            { +                // if this fails we want to utilize normal failover logic, GetKWKID +                // logs error +                bSuccess = pLoadBalancer->GetKWKID(iIndex, lKMAID, pstSoap, +					acKWKID, &bClientAESKeyWrapSetupError) ? true : false; +                if (bSuccess) +                { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveKey2( +                            pstSoap, +                            sURL, +                            NULL, +                            pKeyID, +                            stDataUnit, +                            i_pKeyGroupID ? i_pKeyGroupID : (char *) "", +                            acKWKID, +                            //NOTE: this is ugly but the soap response struct's are the same for both flavors of CreateKey +                            *(reinterpret_cast<struct KMS_Agent::KMS_Agent__RetrieveKey2Response *>(&oResponse))) == SOAP_OK; +                } +            } +            else if (bSuccess)  // NO AES Key Wrap +            { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveKey( +                            pstSoap, +                            sURL, +                            NULL, +                            pKeyID, +                            stDataUnit, +                            i_pKeyGroupID ? i_pKeyGroupID : (char *) "", +                            oResponse) == SOAP_OK; +            } + +            // don'f failover for Client side AES Key Wrap setup problems +            if (!bSuccess && !bClientAESKeyWrapSetupError) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_KEY_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            if (bSuccess) +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess) && (!bClientAESKeyWrapSetupError)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        if (KMS_KEY_ID_SIZE != ConvertUTF8HexStringToBinary( +            oResponse.Key.KeyID, NULL)) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_KEYID_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +    } + +    if (bSuccess) +    { +        ConvertUTF8HexStringToBinary( +                oResponse.Key.KeyID, o_pKey->m_acKeyID); + +        //if ( oResponse.Key.KeyState < (KMS_Agent__KeyState)KMS_KEY_STATE_ACTIVE_PROTECT_AND_PROCESS || +        //    oResponse.Key.KeyState > (KMS_Agent__KeyState)KMS_KEY_STATE_COMPROMISED ) +        if ((KMS_AGENT_KEY_STATE) oResponse.Key.KeyState < KMS_KEY_STATE_ACTIVE_PROTECT_AND_PROCESS || +            (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState > KMS_KEY_STATE_COMPROMISED) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_KEY_STATE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        o_pKey->m_iKeyState = (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState; + +        if ((KMS_KEY_TYPE) oResponse.Key.KeyType != KMS_KEY_TYPE_AES_256) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_KEY_TYPE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        o_pKey->m_iKeyType = (KMS_KEY_TYPE) oResponse.Key.KeyType; + +        if (strlen(oResponse.Key.KeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_KEY_GROUP_ID_LENGTH_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pKey->m_acKeyGroupID, +                    oResponse.Key.KeyGroupID, +                    sizeof(o_pKey->m_acKeyGroupID)); +            o_pKey->m_acKeyGroupID[sizeof(o_pKey->m_acKeyGroupID)-1] = '\0'; +        } + +        if ( bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +        { +            // verify KWK ID matches what was registered +            if (oResponse.Key.Key.__size != KMS_MAX_WRAPPED_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_WRAPPED_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                if (pLoadBalancer->AESKeyUnwrap(&iIndex, oResponse.Key.Key.__ptr, +                    o_pKey->m_acKey) == false) +                { +                    GetPeerNetworkAddress(sKmaAddress, pstSoap); +                    LogError(i_pProfile, +                            AUDIT_CLIENT_AGENT_RETRIEVE_KEY_AESKEYUNWRAP_ERROR, +                            NULL, +                            sKmaAddress, +                            NULL); + +                    bSuccess = false; +                } +            } +        } +        else if (bSuccess) // non-AES key wrap +        { +            if (oResponse.Key.Key.__size != KMS_MAX_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_KEY_INVALID_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                memcpy(o_pKey->m_acKey, +                        oResponse.Key.Key.__ptr, +                        KMS_MAX_KEY_SIZE); +            } +        } + +        if (bSuccess) +        { +            o_pKey->m_iKeyLength = KMS_MAX_KEY_SIZE; + +            if (KMSAgentKeyCallout(o_pKey->m_acKey) != 0) +            { +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_KEY_KEY_CALLOUT_ERROR, +                        NULL, +                        NULL, +                        NULL); +                bSuccess = false; +            } +        } +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, +            bClientAESKeyWrapSetupError ? +                CAgentLoadBalancer::AES_KEY_WRAP_SETUP_ERROR : iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_RetrieveDataUnit ( +                                            KMSClientProfile * const i_pProfile, +                                            const unsigned char * const i_pDataUnitID, +                                            const unsigned char * const i_pExternalUniqueID, +                                            int i_iExternalUniqueIDLen, +                                            utf8cstr const i_pExternalTag, +                                            utf8cstr const i_pDescription, +                                            KMSAgent_DataUnit * const o_pDataUnit) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_RetrieveDataUnit); +#endif + +#if defined(DEBUG) && defined(METAWARE) +    log_printf("KMSAgent_RetrieveDataUnit entered\n"); +#endif + +    // required parms +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pDataUnitID) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnitID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + + + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +#if defined(DEBUG) && defined(METAWARE) +        log_printf("KMSAgent_RetrieveDataUnit profile not loaded\n"); +#endif +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    // validate input parms + +    if (i_pExternalUniqueID && +        (i_iExternalUniqueIDLen <= 0 || +        i_iExternalUniqueIDLen > KMS_MAX_EXTERNAL_UNIQUE_ID_SIZE)) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalUniqueID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pExternalTag && strlen(i_pExternalTag) > KMS_MAX_EXTERNAL_TAG) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalTag arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pDescription && +        strlen(i_pDescription) > KMS_MAX_DESCRIPTION) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Description arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    // prepare args to soap transaction + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__RetrieveDataUnitResponse oResponse; + +    char * pDataUnitID = NULL; +    pDataUnitID = ConvertBinaryDataFromRequest(pstSoap, +            i_pDataUnitID, +            KMS_DATA_UNIT_ID_SIZE); +    //sizeof(DATA_UNIT_ID) ); +    if (pDataUnitID == NULL) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory dont' log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    char * pExternalUniqueID = NULL; +    if (i_pExternalUniqueID) +    { +        pExternalUniqueID = ConvertBinaryDataFromRequest(pstSoap, +                i_pExternalUniqueID, +                i_iExternalUniqueIDLen); +        if (pExternalUniqueID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pExternalTag = NULL; +    if (i_pExternalTag) +    { +        pExternalTag = ConvertUTF8StringFromRequest(pstSoap, +                i_pExternalTag, +                KMS_MAX_EXTERNAL_TAG + 1); +        if (pExternalTag == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pDescription = NULL; +    if (i_pDescription) +    { +        pDescription = ConvertUTF8StringFromRequest(pstSoap, +                i_pDescription, +                KMS_MAX_DESCRIPTION + 1); +        if (pDescription == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->BalanceByDataUnitID(i_pDataUnitID, +            KMS_DATA_UNIT_ID_SIZE); + +    if ( iIndex >= 0 ) +    { +        do +        { +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveDataUnit( +                    pstSoap, +                    sURL, +                    NULL, +                    pDataUnitID, +                    i_pExternalUniqueID ? pExternalUniqueID : (char *) "", +                    i_pExternalTag ? pExternalTag : (char *) "", +                    i_pDescription ? pDescription : (char *) "", +                    oResponse) == SOAP_OK; + +            if (!bSuccess) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.DataUnitID, o_pDataUnit->m_acDataUnitID); + +        o_pDataUnit->m_iExternalUniqueIDLength = ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.ExternalUniqueID, o_pDataUnit->m_acExternalUniqueID); + +        if (strlen(oResponse.DataUnit.ExternalTag) > KMS_MAX_EXTERNAL_TAG) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_RESPONSE_INVALID_EXTERNAL_TAG_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pDataUnit->m_acExternalTag, +                    oResponse.DataUnit.ExternalTag, +                    sizeof(o_pDataUnit->m_acExternalTag)); +            o_pDataUnit->m_acExternalTag[sizeof(o_pDataUnit->m_acExternalTag)-1] = '\0'; +        } + +        if (strlen(oResponse.DataUnit.Description) > KMS_MAX_DESCRIPTION) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_RESPONSE_INVALID_DESCRIPTION_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strcpy(o_pDataUnit->m_acDescription, +                    oResponse.DataUnit.Description); +        } + +        o_pDataUnit->m_iDataUnitState = +                (KMS_AGENT_DATA_UNIT_STATE) oResponse.DataUnit.DataUnitState; +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_RetrieveDataUnitByExternalUniqueID ( +                                                              KMSClientProfile * const i_pProfile, +                                                              const unsigned char* const i_pExternalUniqueID, +                                                              int i_iExternalUniqueIDLen, +                                                              utf8cstr const i_pExternalTag, +                                                              utf8cstr const i_pDescription, +                                                              KMSAgent_DataUnit * const o_pDataUnit) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_RetrieveDataUnitByExternalUniqueID); +#endif + +    // required parms +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pExternalUniqueID) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalUniqueID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    // validate input parms + +    if (i_iExternalUniqueIDLen <= 0 || +        i_iExternalUniqueIDLen > KMS_MAX_EXTERNAL_UNIQUE_ID_SIZE) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalUniqueIDLen arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pExternalTag && strlen(i_pExternalTag) > KMS_MAX_EXTERNAL_TAG) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "ExternalTag arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pDescription && +        strlen(i_pDescription) > KMS_MAX_DESCRIPTION) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Description arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    // prepare args to soap transaction + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__RetrieveDataUnitByExternalUniqueIDResponse oResponse; + +    char * pExternalUniqueID = NULL; +    pExternalUniqueID = ConvertBinaryDataFromRequest(pstSoap, +            i_pExternalUniqueID, +            i_iExternalUniqueIDLen); +    if (pExternalUniqueID == NULL) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory dont' log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    char * pExternalTag = NULL; +    if (i_pExternalTag) +    { +        pExternalTag = ConvertUTF8StringFromRequest(pstSoap, +                i_pExternalTag, +                KMS_MAX_EXTERNAL_TAG + 1); +        if (pExternalTag == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pDescription = NULL; +    if (i_pDescription) +    { +        pDescription = ConvertUTF8StringFromRequest(pstSoap, +                i_pDescription, +                KMS_MAX_DESCRIPTION + 1); +        if (pDescription == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->Balance(); + +    if ( iIndex >= 0 ) +    { +        do +        { +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent:: +                    soap_call_KMS_Agent__RetrieveDataUnitByExternalUniqueID( +                    pstSoap, +                    sURL, +                    NULL, +                    pExternalUniqueID, +                    i_pExternalTag ? pExternalTag : (char *) "", +                    i_pDescription ? pDescription : (char *) "", +                    oResponse) == SOAP_OK; + +            if (!bSuccess) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.DataUnitID, o_pDataUnit->m_acDataUnitID); + +        o_pDataUnit->m_iExternalUniqueIDLength = ConvertUTF8HexStringToBinary( +                oResponse.DataUnit.ExternalUniqueID, +                o_pDataUnit->m_acExternalUniqueID); + +        if (strlen(oResponse.DataUnit.ExternalTag) > KMS_MAX_EXTERNAL_TAG) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_RESPONSE_INVALID_EXTERNAL_TAG_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pDataUnit->m_acExternalTag, +                    oResponse.DataUnit.ExternalTag, +                    sizeof(o_pDataUnit->m_acExternalTag)); +            o_pDataUnit->m_acExternalTag[sizeof(o_pDataUnit->m_acExternalTag)-1] = '\0'; +        } + +        if (strlen(oResponse.DataUnit.Description) > KMS_MAX_DESCRIPTION) +        { +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_BY_EXTERNAL_UNIQUE_ID_RESPONSE_INVALID_DESCRIPTION_LENGTH, +                    NULL, +                    NULL, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strcpy(o_pDataUnit->m_acDescription, +                    oResponse.DataUnit.Description); +        } + +        o_pDataUnit->m_iDataUnitState = +                (KMS_AGENT_DATA_UNIT_STATE) oResponse.DataUnit.DataUnitState; + +        if (bSuccess) +        { +            // RetrieveDataUnitByExternalUniqueID may create a DU so add data unit ID +            // and the KMA IP address to the DU cache +            CDataUnitCache* pDataUnitCache = (CDataUnitCache*) i_pProfile->m_pDataUnitCache; + +            if (i_pProfile->m_iClusterDiscoveryFrequency != 0) // load balancing enabled +            { +                bSuccess = pDataUnitCache->Insert( +                        o_pDataUnit->m_acDataUnitID, +                        KMS_DATA_UNIT_ID_SIZE, +                        NULL, 0, +                        pLoadBalancer->GetApplianceNetworkAddress(iIndex)); +            } +        } +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_RetrieveDataUnitKeys ( +                                                KMSClientProfile * const i_pProfile, +                                                const KMSAgent_DataUnit * const i_pDataUnit, +                                                int i_iPageSize, +                                                int i_iPageOffset, +                                                int* const o_piKeysRemaining, +                                                const unsigned char * const i_pKeyID, +                                                KMSAgent_ArrayOfKeys* * const o_ppKeys) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_RetrieveDataUnitKeys); +#endif + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_piKeysRemaining) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "KeysRemaining arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_ppKeys) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Keys arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (i_pKeyID && i_iPageOffset != 0) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "KeyID and PageOffset are mutually exclusive"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    // validate input parms + +    if (i_iPageSize <= 0 || i_iPageSize > KMS_MAX_PAGE_SIZE) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "PageSize arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_iPageOffset < 0) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_PARAMETERS, +                NULL, +                NULL, +                "PageOffset arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    // prepare args to soap transaction + +    struct KMS_Agent::KMS_Agent__DataUnit stDataUnit = {"", "", "", "", +        (KMS_Agent::KMS_Agent__DataUnitState) 0}; + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__RetrieveDataUnitKeysResponse oResponse; + +    if (!CopyDataUnitFromRequest(pstSoap, +        &stDataUnit, +        i_pDataUnit)) +    { +        soap_destroy(pstSoap); +        soap_end(pstSoap); +        // no memory dont' log +        RETURN(KMS_AGENT_STATUS_NO_MEMORY); +    } + +    char * pKeyID = NULL; +    if (i_pKeyID) +    { +        pKeyID = ConvertBinaryDataFromRequest(pstSoap, +                i_pKeyID, +                KMS_KEY_ID_SIZE); +        if (pKeyID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    UTF8_KEYID acKWKID; +    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; +    bool bClientAESKeyWrapSetupError = false; + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; + +    int iIndex = pLoadBalancer->BalanceByDataUnitID(i_pDataUnit->m_acDataUnitID, +            KMS_DATA_UNIT_ID_SIZE); + +    if (iIndex >= 0) +    { +        do +        { +            bSuccess = true; + +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = 0; + +            Long64 lKMAID = pLoadBalancer->GetKMAID(iIndex); + +            if (bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +            { +                // if this fails we want to utilize normal failover logic, GetKWKID +                // logs error +                bSuccess = pLoadBalancer->GetKWKID(iIndex, lKMAID, pstSoap, +					acKWKID, &bClientAESKeyWrapSetupError) ? true : false; +                if (bSuccess) +                { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveDataUnitKeys2( +                            pstSoap, +                            sURL, +                            NULL, +                            stDataUnit, +                            i_iPageSize, +                            i_iPageOffset, +                            pKeyID, +                            acKWKID, +                            *(reinterpret_cast<struct KMS_Agent::KMS_Agent__RetrieveDataUnitKeys2Response *>(&oResponse))) == SOAP_OK; +                } +            } +            else if (bSuccess)  // No AES Key Wrap +            { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveDataUnitKeys( +                            pstSoap, +                            sURL, +                            NULL, +                            stDataUnit, +                            i_iPageSize, +                            i_iPageOffset, +                            pKeyID, +                            oResponse) == SOAP_OK; +            } + +            // don'f failover for Client side AES Key Wrap setup problems +            if (!bSuccess && !bClientAESKeyWrapSetupError) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            if (bSuccess) +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess) && (!bClientAESKeyWrapSetupError)); +    } +    else +    { +        bSuccess = false; +    } + +    // validate response + +    if (bSuccess && oResponse.KeysRemaining < 0) +    { +        LogError(i_pProfile, +                AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEYS_REMAINING_RESPONSE, +                NULL, +                NULL, +                NULL); +        bSuccess = false; +    } + +    if (bSuccess && +        (oResponse.Keys.__size < 0 || +        oResponse.Keys.__size > i_iPageSize)) +    { +        LogError(i_pProfile, +                AUDIT_CLIENT_AGENT_RETRIEVE_DATA_UNIT_KEYS_INVALID_KEYS_SIZE_RESPONSE, +                NULL, +                NULL, +                NULL); +        bSuccess = false; +    } + +    if ( bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +    { +        // verify KWK ID matches what was registered +    } + +    if (bSuccess) +    { +        *o_ppKeys = CopyDataUnitKeysResponse(i_pProfile, &iIndex, &oResponse.Keys); + +        if (*o_ppKeys == NULL) +        { +            // CopyDataUnitKeysResponse logs errors +            bSuccess = false; +        } +        *o_piKeysRemaining = (int) oResponse.KeysRemaining; +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, +            bClientAESKeyWrapSetupError ? +                CAgentLoadBalancer::AES_KEY_WRAP_SETUP_ERROR : iIndex)); +} + +extern "C" +KMS_AGENT_STATUS KMSAgent_RetrieveProtectAndProcessKey ( +                                                        KMSClientProfile * const i_pProfile, +                                                        const KMSAgent_DataUnit * const i_pDataUnit, +                                                        utf8cstr const i_pKeyGroupID, +                                                        KMSAgent_Key * const o_pKey) +{ +    bool bSuccess; +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_RetrieveProtectAndProcessKey); +#endif + +    if (!i_pProfile || !i_pDataUnit || !o_pKey) +    { +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!i_pDataUnit) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "DataUnit arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!o_pKey) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Key arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_pKeyGroupID && +        strlen(i_pKeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +    { +        Log(AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_PARAMETERS, +                NULL, +                NULL, +                "GroupID arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    struct KMS_Agent::KMS_Agent__DataUnit stDataUnit ={"", "", "", "", +        (KMS_Agent::KMS_Agent__DataUnitState) 0}; + +    struct soap *pstSoap = (struct soap *) i_pProfile->m_pvSoap; +    struct KMS_Agent::KMS_Agent__RetrieveProtectAndProcessKeyResponse oResponse; + +    if (i_pDataUnit != NULL) +    { +        if (!CopyDataUnitFromRequest(pstSoap, +            &stDataUnit, +            i_pDataUnit)) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char * pKeyGroupID = NULL; +    if (i_pKeyGroupID) +    { +        pKeyGroupID = ConvertUTF8StringFromRequest(pstSoap, +                i_pKeyGroupID, +                KMS_MAX_KEY_GROUP_ID_SIZE + 1); +        if (pKeyGroupID == NULL) +        { +            soap_destroy(pstSoap); +            soap_end(pstSoap); +            // no memory dont' log +            RETURN(KMS_AGENT_STATUS_NO_MEMORY); +        } +    } + +    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; +    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; +    bool bClientAESKeyWrapSetupError = false; +    UTF8_KEYID acKWKID; + +    CAgentLoadBalancer *pLoadBalancer = (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; +    int iIndex = pLoadBalancer->BalanceByDataUnitID(i_pDataUnit->m_acDataUnitID, +                                                    KMS_DATA_UNIT_ID_SIZE); + +    if (iIndex >= 0) +    { +        do +        { +            bSuccess = true; +            const char* sURL = pLoadBalancer->GetHTTPSURL( +                    iIndex, +                    i_pProfile->m_iPortForAgentService); + +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); + +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            Long64 lKMAID = pLoadBalancer->GetKMAID(iIndex); + +            if (bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +            { +                // if this fails we want to utilize normal failover logic, GetKWKID +                // logs error +                bSuccess = pLoadBalancer->GetKWKID(iIndex, lKMAID, pstSoap, +                                            acKWKID, &bClientAESKeyWrapSetupError) +											? true : false; +                if (bSuccess) +                { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveProtectAndProcessKey2( +                            pstSoap, +                            sURL, +                            NULL, +                            stDataUnit, +                            i_pKeyGroupID ? i_pKeyGroupID : (char *) "", +                            acKWKID, +                            *(reinterpret_cast<struct KMS_Agent::KMS_Agent__RetrieveProtectAndProcessKey2Response *>(&oResponse))) == SOAP_OK; +                } +            } +            else if (bSuccess)  // No AES Key Wrap +            { +                    bSuccess = KMS_Agent::soap_call_KMS_Agent__RetrieveProtectAndProcessKey( +                            pstSoap, +                            sURL, +                            NULL, +                            stDataUnit, +                            i_pKeyGroupID ? i_pKeyGroupID : (char *) "", +                            oResponse) == SOAP_OK; +            } + +            // don'f failover for Client side AES Key Wrap setup problems +            if (!bSuccess && !bClientAESKeyWrapSetupError) +            { +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                GetSoapFault(sSoapFaultMsg, pstSoap); + +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess) && (!bClientAESKeyWrapSetupError)); +    } +    else +    { +        bSuccess = false; +    } + +    if (bSuccess) +    { +        if (KMS_KEY_ID_SIZE != ConvertUTF8HexStringToBinary( +            oResponse.Key.KeyID, NULL)) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_KEYID_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +    } + +    if (bSuccess) +    { +        ConvertUTF8HexStringToBinary( +                oResponse.Key.KeyID, o_pKey->m_acKeyID); + +        if ((KMS_AGENT_KEY_STATE) oResponse.Key.KeyState < KMS_KEY_STATE_ACTIVE_PROTECT_AND_PROCESS || +            (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState > KMS_KEY_STATE_COMPROMISED) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_KEY_STATE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        o_pKey->m_iKeyState = (KMS_AGENT_KEY_STATE) oResponse.Key.KeyState; + +        if ((KMS_KEY_TYPE) oResponse.Key.KeyType != KMS_KEY_TYPE_AES_256) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_KEY_TYPE_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } + +        o_pKey->m_iKeyType = (KMS_KEY_TYPE) oResponse.Key.KeyType; + +        if (strlen(oResponse.Key.KeyGroupID) > KMS_MAX_KEY_GROUP_ID_SIZE) +        { +            GetPeerNetworkAddress(sKmaAddress, pstSoap); +            LogError(i_pProfile, +                    AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_KEY_GROUP_ID_LENGTH_RESPONSE, +                    NULL, +                    sKmaAddress, +                    NULL); +            bSuccess = false; +        } +        else +        { +            strncpy(o_pKey->m_acKeyGroupID, +                    oResponse.Key.KeyGroupID, +                    sizeof(o_pKey->m_acKeyGroupID)); +            o_pKey->m_acKeyGroupID[sizeof(o_pKey->m_acKeyGroupID)-1] = '\0'; +        } + +        if ( bSuccess && pLoadBalancer->AESKeyWrapSupported(iIndex)) +        { +            // verify KWK ID matches what was registered +            if (oResponse.Key.Key.__size != KMS_MAX_WRAPPED_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_WRAPPED_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                if (pLoadBalancer->AESKeyUnwrap(&iIndex, oResponse.Key.Key.__ptr, +                    o_pKey->m_acKey) == false) +                { +                    GetPeerNetworkAddress(sKmaAddress, pstSoap); +                    LogError(i_pProfile, +                            AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_AESKEYUNWRAP_ERROR, +                            NULL, +                            sKmaAddress, +                            NULL); + +                    bSuccess = false; +                } +            } +        } +        else if (bSuccess) // non-AES key wrap +        { +            if (oResponse.Key.Key.__size != KMS_MAX_KEY_SIZE) +            { +                GetPeerNetworkAddress(sKmaAddress, pstSoap); +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_INVALID_KEY_LENGTH_RESPONSE, +                        NULL, +                        sKmaAddress, +                        NULL); +                bSuccess = false; +            } +            else +            { +                memcpy(o_pKey->m_acKey, +                        oResponse.Key.Key.__ptr, +                        KMS_MAX_KEY_SIZE); +            } +        } + +        if (bSuccess) +        { +            o_pKey->m_iKeyLength = KMS_MAX_KEY_SIZE; + +            if (KMSAgentKeyCallout(o_pKey->m_acKey) != 0) +            { +                LogError(i_pProfile, +                        AUDIT_CLIENT_AGENT_RETRIEVE_PROTECT_AND_PROCESS_KEY_KEY_CALLOUT_ERROR, +                        NULL, +                        NULL, +                        NULL); +                bSuccess = false; +            } +        } +    } + +    if (bSuccess) +    { +        // add Key ID and the creating KMA IP address to the DU cache +        CDataUnitCache* pDataUnitCache = (CDataUnitCache*) i_pProfile->m_pDataUnitCache; + +        if (i_pProfile->m_iClusterDiscoveryFrequency != 0) // load balancing enabled +        { +            bSuccess = pDataUnitCache->Insert( +                    NULL, +                    0, +                    o_pKey->m_acKeyID, +                    KMS_KEY_ID_SIZE, +                    pLoadBalancer->GetApplianceNetworkAddress(iIndex)); +        } +    } +     +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, +            bClientAESKeyWrapSetupError ? +                CAgentLoadBalancer::AES_KEY_WRAP_SETUP_ERROR : iIndex)); +} + +extern "C" +void KMSAgent_FreeArrayOfKeys ( +                               KMSAgent_ArrayOfKeys* i_pArrayOfKeys) +{ +#if defined(METAWARE) +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_FreeArrayOfKeys); +#endif +    if (!i_pArrayOfKeys) +    { +        return; +    } + +    // free memory for all information groups +    if (i_pArrayOfKeys->m_pKeys) +    { +        free(i_pArrayOfKeys->m_pKeys); +    } + +    free(i_pArrayOfKeys); +} + +/*--------------------------------------------------------------------------- + * Function: KMSAgent_CreateAuditLog + * + *--------------------------------------------------------------------------*/ +extern "C" +KMS_AGENT_STATUS KMSAgent_CreateAuditLog ( +                                          KMSClientProfile* i_pProfile, +                                          enum KMS_AUDIT_LOG_RETENTION i_iRetention, +                                          enum KMS_AUDIT_LOG_CONDITION i_iCondition, +                                          int i_bIssueAlert, +                                          utf8cstr i_pMessage) +{ +    bool bSuccess = true; +#ifdef DEBUG_TIMING +    ECPT_TRACE_ENTRY *trace = NULL; +    ECPT_TRACE(trace, KMSAgent_CreateAuditLog); +#endif + +    //   START_STACK_CHECK; + +    if (!i_pProfile) +    { +        Log(AUDIT_CLIENT_AGENT_CREATED_AUDIT_LOG_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Profile arg"); + +        //        END_STACK_CHECK; + +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    // check arguments +    if (i_iRetention > KMS_AUDIT_LOG_SHORT_TERM_RETENTION) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_AUDIT_LOG_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Retention arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (i_iCondition > KMS_AUDIT_LOG_WARNING_CONDITION) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_AUDIT_LOG_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Condition arg"); +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } + +    if (!i_pMessage || (strlen(i_pMessage) <= 0)) +    { +        Log(AUDIT_CLIENT_AGENT_CREATE_AUDIT_LOG_INVALID_PARAMETERS, +                NULL, +                NULL, +                "Message arg"); +        //       END_STACK_CHECK; +        RETURN(KMS_AGENT_STATUS_INVALID_PARAMETER); +    } +    if (!KMSClient_ProfileLoaded(i_pProfile)) +    { +        //        END_STACK_CHECK; +        RETURN(KMS_AGENT_STATUS_PROFILE_NOT_LOADED); +    } + +    CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); + +    struct soap* pstSoap = (struct soap*) i_pProfile->m_pvSoap; + +    // Create Audit Log + +    KMS_Agent::KMS_Agent__CreateAuditLogResponse oResponse; + +    CAgentLoadBalancer *pLoadBalancer = +            (CAgentLoadBalancer *) i_pProfile->m_pAgentLoadBalancer; + +    int iIndex = pLoadBalancer->Balance(); +    if (iIndex >= 0) +    { +        do +        { +            const char* sURL = pLoadBalancer-> +                    GetHTTPSURL(iIndex, i_pProfile->m_iPortForAgentService); +            strncpy(i_pProfile->m_sURL, sURL, sizeof(i_pProfile->m_sURL)); +            i_pProfile->m_sURL[sizeof(i_pProfile->m_sURL)-1] = '\0'; + +            bSuccess = KMS_Agent::soap_call_KMS_Agent__CreateAuditLog( +                    pstSoap, +                    sURL, +                    NULL, +                    (enum KMS_Agent::KMS_Agent__AuditLogRetention)i_iRetention, +                    (enum KMS_Agent::KMS_Agent__AuditLogCondition)i_iCondition, +                    i_bIssueAlert ? true : false, +                    i_pMessage, +                    oResponse) == SOAP_OK; + + +            if (!bSuccess) +            { +                char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; +                char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; + +                GetSoapFault(sSoapFaultMsg, pstSoap); +                GetPeerNetworkAddress(sKmaAddress, pstSoap); + +                iIndex = pLoadBalancer->FailOver(iIndex, pstSoap); + +                LogError(i_pProfile, AUDIT_CLIENT_AGENT_CREATE_AUDIT_LOG_SOAP_ERROR, +                        NULL, +                        sKmaAddress, +                        sSoapFaultMsg); +            } +            else +            { +                pLoadBalancer->UpdateResponseStatus(iIndex); +            } +        } +        while (iIndex >= 0 && (!bSuccess)); +    } +    else +    { +        bSuccess = false; +    } + +    // free allocated memory for output if error condition +    // Clean up SOAP + +    soap_destroy(pstSoap); +    soap_end(pstSoap); + +    if (bSuccess) +    { +        //      END_STACK_CHECK; +        RETURN(KMS_AGENT_STATUS_OK); +    } + +    //   END_STACK_CHECK; +    RETURN(KMSAgent_GetLastStatusCode(i_pProfile, iIndex)); +} + +#ifdef KMSUSERPKCS12 +/* + * This function allows the user to change the PIN on the PKCS12 + * file that holds the clients private key and cert. + */ +extern "C" +KMS_AGENT_STATUS KMSAgent_ChangeLocalPWD( +	KMSClientProfile* i_pProfile, +	utf8cstr const i_pOldPassphrase, +	utf8cstr const i_pNewPassphrase) +{ +	CCertificate *pCert; +	CPrivateKey *pKey; +	bool bSuccess; + +	pCert = new CCertificate; +	pKey = new CPrivateKey; + +	bSuccess = GetPKCS12CertAndKey(i_pProfile, i_pOldPassphrase, +		pCert, pKey); +	if (!bSuccess) +    		return(KMSAgent_GetLastStatusCode(i_pProfile, 0)); + +	bSuccess = StoreAgentPKI(i_pProfile, pCert, pKey, i_pNewPassphrase); +	if (!bSuccess) +    		return(KMSAgent_GetLastStatusCode(i_pProfile, 0)); + +	return (KMS_AGENT_STATUS_OK); +} +#endif /* KMSUSERPKCS12 */ | 
