/*============================================================================
 * Create a server socket
 *===========================================================================*/
OpcUa_StatusCode OPCUA_DLLCALL OpcUa_P_SocketManager_CreateServer(  OpcUa_SocketManager         a_pSocketManager,
                                                                    OpcUa_StringA               a_sAddress,
                                                                    OpcUa_Boolean               a_bListenOnAllInterfaces,
                                                                    OpcUa_Socket_EventCallback  a_pfnSocketCallBack,
                                                                    OpcUa_Void*                 a_pCallbackData,
                                                                    OpcUa_Socket*               a_pSocket)
{
    OpcUa_InternalSocketManager*    pInternalSocketManager  = OpcUa_Null;
    OpcUa_UInt16                    uPort                   = 0;
    OpcUa_StringA                   sRemoteAdress           = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_Socket, "CreateServer");

#if !OPCUA_MULTITHREADED
    if(a_pSocketManager == OpcUa_Null)
    {
        a_pSocketManager = OpcUa_Socket_g_SocketManager;
    }
#endif

    OpcUa_ReturnErrorIfArgumentNull(a_pSocketManager);
    OpcUa_ReturnErrorIfArgumentNull(a_pSocket);

    pInternalSocketManager = (OpcUa_InternalSocketManager*)a_pSocketManager;

    /* parse address */
    uStatus = OpcUa_P_ParseUrl( a_sAddress,
                                &sRemoteAdress,
                                &uPort);

    OpcUa_ReturnErrorIfBad(uStatus);
    if(a_bListenOnAllInterfaces)
    {
        if(sRemoteAdress != OpcUa_Null)
        {
            OpcUa_P_Memory_Free(sRemoteAdress);
            sRemoteAdress = OpcUa_Null;
        }
    }

    uStatus = OpcUa_SocketManager_InternalCreateServer( pInternalSocketManager,
                                                        sRemoteAdress,
                                                        uPort,
                                                        a_pfnSocketCallBack,
                                                        a_pCallbackData,
                                                        a_pSocket);
    OpcUa_GotoErrorIfBad(uStatus);


    OpcUa_P_SocketManager_InterruptLoop(pInternalSocketManager,
                                        OPCUA_SOCKET_RENEWLOOP_EVENT,
                                        OpcUa_False);

    if(sRemoteAdress != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(sRemoteAdress);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(sRemoteAdress != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(sRemoteAdress);
    }

OpcUa_FinishErrorHandling;
}
/*===========================================================================*
OpcUa_P_OpenSSL_RSA_Public_Encrypt
*===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_RSA_Public_Encrypt(
    OpcUa_CryptoProvider*   a_pProvider,
    OpcUa_Byte*             a_pPlainText,
    OpcUa_UInt32            a_plainTextLen,
    OpcUa_Key*              a_publicKey,
    OpcUa_Int16             a_padding,
    OpcUa_Byte*             a_pCipherText,
    OpcUa_UInt32*           a_pCipherTextLen)
{
    EVP_PKEY*       pPublicKey      = OpcUa_Null;

    OpcUa_UInt32    uKeySize            = 0;
    OpcUa_UInt32    uEncryptedDataSize  = 0;
    OpcUa_UInt32    uPlainTextPosition  = 0;
    OpcUa_UInt32    uCipherTextPosition = 0;
    OpcUa_UInt32    uBytesToEncrypt     = 0;
    OpcUa_Int32     iEncryptedBytes     = 0;
    const unsigned char *pData;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "RSA_Public_Encrypt");

    OpcUa_ReferenceParameter(a_pProvider);

    OpcUa_ReturnErrorIfArgumentNull(a_publicKey);
    OpcUa_ReturnErrorIfArgumentNull(a_publicKey->Key.Data);
    OpcUa_ReturnErrorIfArgumentNull(a_pCipherTextLen);

    *a_pCipherTextLen = 0;

    if((OpcUa_Int32)a_plainTextLen < 1)
    {
        uStatus = OpcUa_BadInvalidArgument;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_publicKey->Type != OpcUa_Crypto_KeyType_Rsa_Public)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadInvalidArgument);
    }

    pData = a_publicKey->Key.Data;
    pPublicKey = d2i_PublicKey(EVP_PKEY_RSA, OpcUa_Null, &pData, a_publicKey->Key.Length);

    if ( pPublicKey != OpcUa_Null )
    {
        uKeySize = RSA_size(pPublicKey->pkey.rsa);
    }
    else
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadInvalidArgument);
    }

    /* check padding type */
    switch(a_padding)
    {
    case RSA_PKCS1_PADDING:
        {
            uEncryptedDataSize = uKeySize - 11;
            break;
        }
    case RSA_PKCS1_OAEP_PADDING:
        {
            uEncryptedDataSize = uKeySize - 42;
            break;
        }
    case RSA_NO_PADDING:
        {
            uEncryptedDataSize = uKeySize;
            break;
        }
    default:
        {
            OpcUa_GotoErrorWithStatus(OpcUa_BadNotSupported);
        }
    }

    if(a_plainTextLen < uEncryptedDataSize)
    {
        uBytesToEncrypt = a_plainTextLen;
    }
    else
    {
        uBytesToEncrypt = uEncryptedDataSize;
    }

    while(uPlainTextPosition < a_plainTextLen)
    {

        /* the last part could be smaller */
        if((a_plainTextLen >= uEncryptedDataSize) && ((a_plainTextLen - uPlainTextPosition) < uEncryptedDataSize))
        {
            uBytesToEncrypt = a_plainTextLen - uPlainTextPosition;
        }

        if((a_pCipherText != OpcUa_Null) && (a_pPlainText != OpcUa_Null))
        {
            iEncryptedBytes = RSA_public_encrypt(   uBytesToEncrypt,      /* how much to encrypt  */
                                                    a_pPlainText + uPlainTextPosition,      /* what to encrypt      */
                                                    a_pCipherText + uCipherTextPosition,/* where to encrypt     */
                                                    pPublicKey->pkey.rsa,                  /* public key           */
                                                    a_padding);        /* padding mode         */
            if(iEncryptedBytes < 0)
            {
                const char*     sError          = OpcUa_Null;
                unsigned long   error           = 0;

                error = ERR_get_error();

                ERR_load_crypto_strings();

                sError = ERR_reason_error_string(error);
                sError = ERR_func_error_string(error);
                sError = ERR_lib_error_string(error);

                uStatus = OpcUa_Bad;
                OpcUa_GotoError;
            }

        }
        else
        {
            iEncryptedBytes = uKeySize;
        }

        *a_pCipherTextLen = *a_pCipherTextLen + iEncryptedBytes;
        uCipherTextPosition += uKeySize;
        uPlainTextPosition  += uBytesToEncrypt;
    }

    EVP_PKEY_free(pPublicKey);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pPublicKey != OpcUa_Null)
    {
        EVP_PKEY_free(pPublicKey);
    }

    *a_pCipherTextLen = (OpcUa_UInt32)-1;

OpcUa_FinishErrorHandling;
}
static
OpcUa_StatusCode OpcUa_UadpDataSetMessageHeader_WriteBinary(OpcUa_UadpDataSetMessageHeader* a_pValue, OpcUa_Byte **a_pBuffer, OpcUa_UInt32 *a_pSize)
{
    OpcUa_Byte dataSetFlags1;
    OpcUa_Byte dataSetFlags2;

    OpcUa_InitializeStatus(OpcUa_Module_PubSub, "OpcUa_UadpDataSetMessageHeader_WriteBinary");

    OpcUa_ReturnErrorIfArgumentNull(a_pValue);
    OpcUa_ReturnErrorIfArgumentNull(a_pBuffer);
    OpcUa_ReturnErrorIfArgumentNull(*a_pBuffer);
    OpcUa_ReturnErrorIfArgumentNull(a_pSize);

    /* Flags 1 */
    /* Bit 0 DataSetMessage is valid */
    /* Bit 1-2 Field Encoding */
    /* Bit 3 SequenceNumber enabled */
    /* Bit 4 Status enabled */
    /* Bit 5 Major Version */
    /* Bit 6 Minor Version */
    dataSetFlags1 = (OpcUa_Byte)a_pValue->DataSetEncodingFlags & 0x79;
    dataSetFlags1 |= (OpcUa_Byte)a_pValue->FieldEncoding << 1;

    /* Flags 2 */
    /* Bits 0-3 MessageType */
    /* Bit 4 Timestamp */
    /* Bit 5 PicoSeconds */
    dataSetFlags2 = (OpcUa_Byte)((a_pValue->DataSetEncodingFlags & 0x3000) >> 8);
    dataSetFlags2 |= a_pValue->DataSetMessageType;

    if(dataSetFlags2)
    {
        dataSetFlags1 |= 0x80;
    }

    OpcUa_UadpEncode_Direct(Byte, &dataSetFlags1);

    if(dataSetFlags2)
    {
        OpcUa_UadpEncode_Direct(Byte, &dataSetFlags2);
    }

    if(a_pValue->DataSetEncodingFlags & OpcUa_UadpDataMessage_FlagsEncodingBit_SequenceNumber)
    {
        OpcUa_UadpEncode_Direct(UInt16, &a_pValue->DataSetMessageSequenceNumber);
    }
    if(a_pValue->DataSetMessageType != OpcUa_DataSetMessageType_KeepAlive)
    {
        a_pValue->DataSetMessageSequenceNumber++;
    }
    if(a_pValue->DataSetEncodingFlags & OpcUa_UadpDataMessage_FlagsEncodingBit_Timestamp)
    {
        /* convert structure to UInt64 */
        OpcUa_UInt64 timeValue;
        timeValue = (OpcUa_UInt32)a_pValue->Timestamp.dwHighDateTime;
        timeValue <<= 32;
        timeValue += (OpcUa_UInt32)a_pValue->Timestamp.dwLowDateTime;
        OpcUa_UadpEncode_Direct(UInt64, &timeValue);
    }
    if(a_pValue->DataSetEncodingFlags & OpcUa_UadpDataMessage_FlagsEncodingBit_PicoSeconds)
    {
        OpcUa_UadpEncode_Direct(UInt16, &a_pValue->PicoSeconds);
    }
    if(a_pValue->DataSetEncodingFlags & OpcUa_UadpDataMessage_FlagsEncodingBit_Status)
    {
        /* Write only the 2 high order Bytes */
        OpcUa_UInt16 statusCode = (a_pValue->StatusCode >> 16);
        OpcUa_UadpEncode_Direct(UInt16, &statusCode);
    }
/*============================================================================
 * OpcUa_P_PKIFactory_CreatePKIProvider
 *===========================================================================*/
OpcUa_StatusCode OPCUA_DLLCALL OpcUa_P_PKIFactory_CreatePKIProvider(OpcUa_Void*         a_pCertificateStoreConfig,
                                                                    OpcUa_PKIProvider*  a_pPkiProvider)
{
    OpcUa_P_OpenSSL_CertificateStore_Config*    pCertificateStoreCfg    = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_P_PKIFactory, "CreatePKIProvider");

    OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStoreConfig);
    OpcUa_ReturnErrorIfArgumentNull(a_pPkiProvider);

    pCertificateStoreCfg = (OpcUa_P_OpenSSL_CertificateStore_Config*)a_pCertificateStoreConfig;
    a_pPkiProvider->Handle = a_pCertificateStoreConfig;

    switch(pCertificateStoreCfg->PkiType)
    {
    case OpcUa_NO_PKI:
        {
            a_pPkiProvider->OpenCertificateStore    = OpcUa_P_OpenSSL_PKI_NoSecurity_OpenCertificateStore;
            a_pPkiProvider->CloseCertificateStore   = OpcUa_P_OpenSSL_PKI_NoSecurity_CloseCertificateStore;
            a_pPkiProvider->ValidateCertificate     = OpcUa_P_OpenSSL_PKI_NoSecurity_ValidateCertificate;
            a_pPkiProvider->LoadCertificate         = OpcUa_P_OpenSSL_PKI_NoSecurity_LoadCertificate;
            a_pPkiProvider->SaveCertificate         = OpcUa_P_OpenSSL_PKI_NoSecurity_SaveCertificate;
            a_pPkiProvider->LoadPrivateKeyFromFile  = OpcUa_P_OpenSSL_PKI_NoSecurity_LoadPrivateKeyFromFile;
            a_pPkiProvider->ExtractCertificateData  = OpcUa_P_OpenSSL_PKI_NoSecurity_ExtractCertificateData;
            break;
        }
#if OPCUA_SUPPORT_PKI
#if OPCUA_SUPPORT_PKI_OVERRIDE
    case OpcUa_Override:
        {
            /* check if replacement for default is set and use it instead of the default */
            OpcUa_PKIProvider* pOverride = (OpcUa_PKIProvider*)pCertificateStoreCfg->Override;

            OpcUa_GotoErrorIfArgumentNull(pOverride);

            if(pOverride->OpenCertificateStore == OpcUa_Null)
            {
                a_pPkiProvider->OpenCertificateStore = OpcUa_P_OpenSSL_PKI_OpenCertificateStore;
            }
            else
            {
                a_pPkiProvider->OpenCertificateStore = pOverride->OpenCertificateStore;
            }

            if(pOverride->CloseCertificateStore == OpcUa_Null)
            {
                a_pPkiProvider->CloseCertificateStore = OpcUa_P_OpenSSL_PKI_CloseCertificateStore;
            }
            else
            {
                a_pPkiProvider->CloseCertificateStore = pOverride->CloseCertificateStore;
            }

            if(pOverride->ValidateCertificate == OpcUa_Null)
            {
                a_pPkiProvider->ValidateCertificate = OpcUa_P_OpenSSL_PKI_ValidateCertificate;
            }
            else
            {
                a_pPkiProvider->ValidateCertificate = pOverride->ValidateCertificate;
            }

            if(pOverride->LoadCertificate == OpcUa_Null)
            {
                a_pPkiProvider->LoadCertificate = OpcUa_P_OpenSSL_PKI_LoadCertificate;
            }
            else
            {
                a_pPkiProvider->LoadCertificate = pOverride->LoadCertificate;
            }

            if(pOverride->SaveCertificate == OpcUa_Null)
            {
                a_pPkiProvider->SaveCertificate = OpcUa_P_OpenSSL_PKI_SaveCertificate;
            }
            else
            {
                a_pPkiProvider->SaveCertificate = pOverride->SaveCertificate;
            }

            if(pOverride->LoadPrivateKeyFromFile == OpcUa_Null)
            {
                a_pPkiProvider->LoadPrivateKeyFromFile = OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile;
            }
            else
            {
                a_pPkiProvider->LoadPrivateKeyFromFile = pOverride->LoadPrivateKeyFromFile;
            }

            if(pOverride->ExtractCertificateData == OpcUa_Null)
            {
                a_pPkiProvider->ExtractCertificateData = OpcUa_P_OpenSSL_PKI_ExtractCertificateData;
            }
            else
            {
                a_pPkiProvider->ExtractCertificateData = pOverride->ExtractCertificateData;
            }
            break;
        }
#endif /* OPCUA_SUPPORT_PKI_OVERRIDE */
#if OPCUA_SUPPORT_PKI_OPENSSL
    case OpcUa_OpenSSL_PKI:
        {
            a_pPkiProvider->OpenCertificateStore    = OpcUa_P_OpenSSL_PKI_OpenCertificateStore;
            a_pPkiProvider->CloseCertificateStore   = OpcUa_P_OpenSSL_PKI_CloseCertificateStore;
            a_pPkiProvider->ValidateCertificate     = OpcUa_P_OpenSSL_PKI_ValidateCertificate;
            a_pPkiProvider->LoadCertificate         = OpcUa_P_OpenSSL_PKI_LoadCertificate;
            a_pPkiProvider->SaveCertificate         = OpcUa_P_OpenSSL_PKI_SaveCertificate;
            a_pPkiProvider->LoadPrivateKeyFromFile  = OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile;
            a_pPkiProvider->ExtractCertificateData  = OpcUa_P_OpenSSL_PKI_ExtractCertificateData;
            break;
        }
#endif /* OPCUA_SUPPORT_PKI_OPENSSL */
#if OPCUA_SUPPORT_PKI_WIN32
    case OpcUa_Win32_PKI:
        {
            a_pPkiProvider->OpenCertificateStore    = OpcUa_P_Win32_PKI_OpenCertificateStore;
            a_pPkiProvider->CloseCertificateStore   = OpcUa_P_Win32_PKI_CloseCertificateStore;
            a_pPkiProvider->ValidateCertificate     = OpcUa_P_Win32_PKI_ValidateCertificate;
            a_pPkiProvider->LoadCertificate         = OpcUa_P_Win32_PKI_LoadCertificate;
            a_pPkiProvider->SaveCertificate         = OpcUa_P_Win32_PKI_SaveCertificate;
            a_pPkiProvider->LoadPrivateKeyFromFile  = OpcUa_P_Win32_LoadPrivateKeyFromKeyStore;
            a_pPkiProvider->ExtractCertificateData  = OpcUa_P_OpenSSL_PKI_ExtractCertificateData;
            break;
        }
#endif /* OPCUA_SUPPORT_PKI_WIN32 */
#endif /* OPCUA_SUPPORT_PKI */
    default:
        {
            uStatus = OpcUa_BadNotSupported;
        }
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_ProxyStub_Initialize
 *===========================================================================*/
OpcUa_StatusCode OPCUA_DLLCALL OpcUa_ProxyStub_Initialize(OpcUa_Handle                  a_pPlatformLayerCalltable,
                                                          OpcUa_ProxyStubConfiguration* a_pProxyStubConfiguration)
{
    OpcUa_Boolean bSkip = OpcUa_False;

OpcUa_InitializeStatus(OpcUa_Module_ProxyStub, "Initialize");

    OpcUa_ReturnErrorIfArgumentNull(a_pProxyStubConfiguration)
    OpcUa_ReturnErrorIfArgumentNull(a_pPlatformLayerCalltable);

    /* set global platform layer handle */
    OpcUa_ProxyStub_g_PlatformLayerCalltable = (OpcUa_Port_CallTable *)a_pPlatformLayerCalltable;

#if OPCUA_USE_SYNCHRONISATION
    if(OpcUa_ProxyStub_g_hGlobalsMutex == OpcUa_Null)
    {
        uStatus = OPCUA_P_MUTEX_CREATE(&OpcUa_ProxyStub_g_hGlobalsMutex);
        OpcUa_GotoErrorIfBad(uStatus);
    }
#endif /* OPCUA_USE_SYNCHRONISATION */

#if OPCUA_USE_SYNCHRONISATION
    OPCUA_P_MUTEX_LOCK(OpcUa_ProxyStub_g_hGlobalsMutex);
#endif /* OPCUA_USE_SYNCHRONISATION */

    OpcUa_ProxyStub_g_uNoOfInits++;

    if(OpcUa_ProxyStub_g_uNoOfInits > 1)
    {
        bSkip = OpcUa_True;
    }

#if OPCUA_USE_SYNCHRONISATION
    OPCUA_P_MUTEX_UNLOCK(OpcUa_ProxyStub_g_hGlobalsMutex);
#endif /* OPCUA_USE_SYNCHRONISATION */

    if(bSkip == OpcUa_False)
    {
        /* set global configuration object */
        uStatus = OpcUa_ProxyStub_ReInitialize(a_pProxyStubConfiguration);
        OpcUa_GotoErrorIfBad(uStatus);

        /* initialize tracer */
#if OPCUA_TRACE_ENABLE
        uStatus = OpcUa_Trace_Initialize();
        OpcUa_GotoErrorIfBad(uStatus);
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "OpcUa_ProxyStub_Initialize: Tracer has been initialized!\n");
#endif /* OPCUA_TRACE_ENABLE */

        /* initialize networking. */
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "OpcUa_ProxyStub_Initialize: Network Module...\n");
        uStatus = OPCUA_P_INITIALIZENETWORK();
        OpcUa_GotoErrorIfBad(uStatus);
        OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "OpcUa_ProxyStub_Initialize: Network Module done!\n");

        uStatus = OpcUa_EncodeableTypeTable_Create(&OpcUa_ProxyStub_g_EncodeableTypes);
        OpcUa_GotoErrorIfBad(uStatus);

        uStatus = OpcUa_EncodeableTypeTable_AddTypes(&OpcUa_ProxyStub_g_EncodeableTypes, OpcUa_KnownEncodeableTypes);
        OpcUa_GotoErrorIfBad(uStatus);

        OpcUa_StringTable_Initialize(&OpcUa_ProxyStub_g_NamespaceUris);
        uStatus = OpcUa_StringTable_AddStringList(&OpcUa_ProxyStub_g_NamespaceUris, OpcUa_ProxyStub_StandardNamespaceUris);
        OpcUa_GotoErrorIfBad(uStatus);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_ProxyStub_Clear();

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_PKI_ValidateCertificate
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_ValidateCertificate(
    OpcUa_PKIProvider*          a_pProvider,
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_Void*                 a_pCertificateStore,
    OpcUa_Int*                  a_pValidationCode /* Validation return codes from OpenSSL */
    )
{
    OpcUa_P_OpenSSL_CertificateStore_Config*    pCertificateStoreCfg;

    const unsigned char* p;

    X509*               pX509Certificate        = OpcUa_Null;
    STACK_OF(X509)*     pX509Chain              = OpcUa_Null;
    X509_STORE_CTX*     verify_ctx              = OpcUa_Null;    /* holds data used during verification process */
    char                CertFile[MAX_PATH];
    struct dirent **dirlist = NULL;
    int numCertificates = 0, i;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_ValidateCertificate");

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore);
    OpcUa_ReturnErrorIfArgumentNull(a_pValidationCode);

    pCertificateStoreCfg = (OpcUa_P_OpenSSL_CertificateStore_Config*)a_pProvider->Handle;

    /* convert DER encoded bytestring certificate to openssl X509 certificate */
    p = a_pCertificate->Data;
    if(!(pX509Certificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Length)))
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

    while(p < a_pCertificate->Data + a_pCertificate->Length)
    {
        X509* pX509AddCertificate;
        if(!(pX509AddCertificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Data + a_pCertificate->Length - p)))
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
        if(pX509Chain == NULL)
        {
            pX509Chain = sk_X509_new_null();
            OpcUa_GotoErrorIfAllocFailed(pX509Chain);
        }
        if(!sk_X509_push(pX509Chain, pX509AddCertificate))
        {
            X509_free(pX509AddCertificate);
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
    }

    /* create verification context and initialize it */
    if(!(verify_ctx = X509_STORE_CTX_new()))
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
    if(X509_STORE_CTX_init(verify_ctx, (X509_STORE*)a_pCertificateStore, pX509Certificate, pX509Chain) != 1)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }
#else
    X509_STORE_CTX_init(verify_ctx, (X509_STORE*)a_pCertificateStore, pX509Certificate, pX509Chain);
#endif

    if(X509_STORE_CTX_set_app_data(verify_ctx, pCertificateStoreCfg) != 1)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

    if((pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL) == OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL_EXCEPT_SELF_SIGNED
        && !verify_ctx->check_issued(verify_ctx, pX509Certificate, pX509Certificate))
    {
        /* set the flags of the store so that CRLs are consulted */
        X509_STORE_CTX_set_flags(verify_ctx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    }

    /* verify the certificate */
    *a_pValidationCode = X509_V_OK;
    if(X509_verify_cert(verify_ctx) <= 0)
    {
        *a_pValidationCode = verify_ctx->error;
        switch(verify_ctx->error)
        {
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_CRL_NOT_YET_VALID:
        case X509_V_ERR_CRL_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
            {
                uStatus = OpcUa_BadCertificateTimeInvalid;
                break;
            }
        case X509_V_ERR_CERT_REVOKED:
            {
                uStatus = OpcUa_BadCertificateRevoked;
                break;
            }
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
            {
                uStatus = OpcUa_BadCertificateUntrusted;
                break;
            }
        case X509_V_ERR_CERT_SIGNATURE_FAILURE:
            {
                uStatus = OpcUa_BadSecurityChecksFailed;
                break;
            }
        default:
            {
                uStatus = OpcUa_BadCertificateInvalid;
            }
        }
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_REQUIRE_CHAIN_CERTIFICATE_IN_TRUST_LIST)
    {
        FILE*            pCertificateFile;
        X509*            pTrustCert;
        STACK_OF(X509)*  chain;
        int              trusted, n;

        chain = X509_STORE_CTX_get_chain(verify_ctx);
        trusted = 0;
        if(pCertificateStoreCfg->CertificateTrustListLocation == NULL || pCertificateStoreCfg->CertificateTrustListLocation[0] == '\0')
        {
            uStatus = OpcUa_Bad;
            OpcUa_GotoErrorIfBad(uStatus);
        }

        numCertificates = scandir(pCertificateStoreCfg->CertificateTrustListLocation, &dirlist, certificate_filter_der, alphasort);
        for (i=0; i<numCertificates; i++)
        {
            uStatus = OpcUa_P_OpenSSL_BuildFullPath(pCertificateStoreCfg->CertificateTrustListLocation, dirlist[i]->d_name, MAX_PATH, CertFile);
            OpcUa_GotoErrorIfBad(uStatus);

            /* read DER certificates */
            pCertificateFile = fopen(CertFile, "r");
            if(pCertificateFile == OpcUa_Null)
            {
                continue; /* ignore access errors */
            }

            pTrustCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null);
            fclose(pCertificateFile);
            if(pTrustCert == OpcUa_Null)
            {
                continue; /* ignore parse errors */
            }

            for(n = 0; n < sk_X509_num(chain); n++)
            {
                if (X509_cmp(sk_X509_value(chain, n), pTrustCert) == 0)
                    break;
            }

            X509_free(pTrustCert);
            if(n < sk_X509_num(chain))
            {
                trusted = 1;
                break;
            }
        }
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
        dirlist = NULL;

        if(!trusted)
        {
            uStatus = OpcUa_BadCertificateUntrusted;
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }

    X509_STORE_CTX_free(verify_ctx);
    X509_free(pX509Certificate);
    if(pX509Chain != OpcUa_Null)
    {
        sk_X509_pop_free(pX509Chain, X509_free);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(dirlist != NULL)
    {
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
    }

    if(verify_ctx != OpcUa_Null)
    {
        X509_STORE_CTX_free(verify_ctx);
    }

    if(pX509Certificate != OpcUa_Null)
    {
        X509_free(pX509Certificate);
    }

    if(pX509Chain != OpcUa_Null)
    {
        sk_X509_pop_free(pX509Chain, X509_free);
    }

OpcUa_FinishErrorHandling;
}
/*
    ToDo:   Create Access to OpenSSL certificate store
            => Only API to In-Memory-Store is available for version 0.9.8x
            => Wait until Directory- and/or File-Store is available
*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_LoadCertificate(
    OpcUa_PKIProvider*          a_pProvider,
    OpcUa_Void*                 a_pLoadHandle,
    OpcUa_Void*                 a_pCertificateStore,
    OpcUa_ByteString*           a_pCertificate)
{
    OpcUa_Byte*     buf                 = OpcUa_Null;
    OpcUa_Byte*     p                   = OpcUa_Null;
    FILE*           pCertificateFile    = OpcUa_Null;
    X509*           pTmpCert            = OpcUa_Null;

    OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_LoadCertificate");

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle);
    OpcUa_ReturnErrorIfArgumentNull(a_pLoadHandle);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);

    /* read DER certificates */
    pCertificateFile = fopen((const char*)a_pLoadHandle, "r");

    /* check for valid file handle */
    OpcUa_GotoErrorIfTrue((pCertificateFile == OpcUa_Null), OpcUa_BadInvalidArgument);

    if(!(pTmpCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null)))
    {
        uStatus = OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    a_pCertificate->Length = i2d_X509(pTmpCert, NULL);
    buf = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertificate->Length);
    OpcUa_GotoErrorIfAllocFailed(buf);
    p = buf;
    for (;;)
    {
        i2d_X509(pTmpCert, &p);
        X509_free(pTmpCert);
        if(!(pTmpCert = d2i_X509_fp(pCertificateFile, (X509**)OpcUa_Null)))
        {
            break;
        }
        p = OpcUa_P_Memory_ReAlloc(buf, a_pCertificate->Length + i2d_X509(pTmpCert, NULL));
        OpcUa_GotoErrorIfAllocFailed(p);
        buf = p;
        p = buf + a_pCertificate->Length;
        a_pCertificate->Length += i2d_X509(pTmpCert, NULL);
    }

    if(fclose(pCertificateFile) != 0)
    {
        pCertificateFile = OpcUa_Null;
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    a_pCertificate->Data = buf;

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pCertificateFile != OpcUa_Null)
    {
        fclose(pCertificateFile);
    }

    if(pTmpCert != OpcUa_Null)
    {
        X509_free(pTmpCert);
    }

    if(buf != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(buf);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_TcpSecureChannel_GetCurrentSecuritySet
 *===========================================================================*/
OpcUa_StatusCode OpcUa_TcpSecureChannel_GetCurrentSecuritySet(  OpcUa_SecureChannel*    a_pSecureChannel,
                                                                OpcUa_UInt32*           a_puTokenId,
                                                                OpcUa_SecurityKeyset**  a_ppReceivingKeyset,
                                                                OpcUa_SecurityKeyset**  a_ppSendingKeyset,
                                                                OpcUa_CryptoProvider**  a_ppCryptoProvider)
{
OpcUa_InitializeStatus(OpcUa_Module_SecureChannel, "GetCurrentSecuritySet");

    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel);

    OPCUA_SECURECHANNEL_LOCK(a_pSecureChannel);

    if(a_pSecureChannel->bCurrentTokenActive != OpcUa_False)
    {
        OpcUa_Trace(OPCUA_TRACE_LEVEL_DEBUG, "GetCurrentSecuritySet: Current Keysets requested. Returned token id is %u\n", a_pSecureChannel->CurrentChannelSecurityToken.TokenId);

        if(a_puTokenId != OpcUa_Null)
        {
            *a_puTokenId = a_pSecureChannel->CurrentChannelSecurityToken.TokenId;
        }

        if(a_ppReceivingKeyset != OpcUa_Null)
        {
            *a_ppReceivingKeyset = a_pSecureChannel->pCurrentReceivingKeyset;
        }

        if(a_ppSendingKeyset != OpcUa_Null)
        {
            *a_ppSendingKeyset = a_pSecureChannel->pCurrentSendingKeyset;
        }

        if(a_ppCryptoProvider != OpcUa_Null)
        {
            *a_ppCryptoProvider = a_pSecureChannel->pCurrentCryptoProvider;
        }
    }
    else
    {
        OpcUa_Trace(OPCUA_TRACE_LEVEL_DEBUG, "GetCurrentSecuritySet: Current Keysets requested. Inactive. Returned token id is %u\n", a_pSecureChannel->PreviousChannelSecurityToken.TokenId);

        if(a_puTokenId != OpcUa_Null)
        {
            *a_puTokenId = a_pSecureChannel->PreviousChannelSecurityToken.TokenId;
        }

        if(a_ppReceivingKeyset != OpcUa_Null)
        {
            *a_ppReceivingKeyset = a_pSecureChannel->pPreviousReceivingKeyset;
        }

        if(a_ppSendingKeyset != OpcUa_Null)
        {
            *a_ppSendingKeyset = a_pSecureChannel->pPreviousSendingKeyset;
        }

        if(a_ppCryptoProvider != OpcUa_Null)
        {
            *a_ppCryptoProvider = a_pSecureChannel->pPreviousCryptoProvider;
        }
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_X509_SelfSigned_Custom_Create
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_X509_SelfSigned_Custom_Create(
    OpcUa_CryptoProvider*       a_pProvider,
    OpcUa_Int32                 a_serialNumber,
    OpcUa_UInt32                a_validToInSec,
    OpcUa_Crypto_NameEntry*     a_pNameEntries,      /* will be used for issuer and subject thus it's selfigned cert */
    OpcUa_UInt                  a_nameEntriesCount,  /* will be used for issuer and subject thus it's selfigned cert */
    OpcUa_Key                   a_pSubjectPublicKey, /* EVP_PKEY* - type defines also public key algorithm */
    OpcUa_Crypto_Extension*     a_pExtensions,
    OpcUa_UInt                  a_extensionsCount,
    OpcUa_UInt                  a_signatureHashAlgorithm, /* EVP_sha1(),... */
    OpcUa_Key                   a_pIssuerPrivateKey, /* EVP_PKEY* - type defines also signature algorithm */
    OpcUa_ByteString*           a_pCertificate)
{
    OpcUa_UInt          i;

    X509_NAME*          pSubj               = OpcUa_Null;
    X509V3_CTX          ctx;
    const EVP_MD*       pDigest             = OpcUa_Null;

    X509*               pCert               = OpcUa_Null;
    EVP_PKEY*           pSubjectPublicKey   = OpcUa_Null;
    EVP_PKEY*           pIssuerPrivateKey   = OpcUa_Null;

    OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_SelfSigned_Custom_Create");

    OpcUa_ReferenceParameter(a_pProvider);

    OpcUa_ReturnErrorIfArgumentNull(a_pNameEntries);
    OpcUa_ReturnErrorIfArgumentNull(a_pExtensions);
    OpcUa_ReturnErrorIfArgumentNull(a_pIssuerPrivateKey.Key.Data);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);

    if(a_pSubjectPublicKey.Type != OpcUa_Crypto_KeyType_Rsa_Public)
    {
        uStatus =  OpcUa_BadInvalidArgument;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pIssuerPrivateKey.Type != OpcUa_Crypto_KeyType_Rsa_Private)
    {
        uStatus =  OpcUa_BadInvalidArgument;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    pSubjectPublicKey = d2i_PublicKey(EVP_PKEY_RSA,OpcUa_Null,((const unsigned char**)&(a_pSubjectPublicKey.Key.Data)),a_pSubjectPublicKey.Key.Length);
    if(pSubjectPublicKey == OpcUa_Null)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    pIssuerPrivateKey = d2i_PrivateKey(EVP_PKEY_RSA,OpcUa_Null,((const unsigned char**)&(a_pIssuerPrivateKey.Key.Data)),a_pIssuerPrivateKey.Key.Length);
    if(pIssuerPrivateKey == OpcUa_Null)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* create new certificate object */
    pCert = X509_new();
    if(pCert == OpcUa_Null)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* set version of certificate (V3 since internal representation starts versioning from 0) */
    if(X509_set_version(pCert, 2L) != 1)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* generate a unique number for a serial number if none provided. */
    if(a_serialNumber == 0)
    {
        ASN1_INTEGER* pSerialNumber = X509_get_serialNumber(pCert);

        pSerialNumber->type   = V_ASN1_INTEGER;
        pSerialNumber->data   = OPENSSL_realloc(pSerialNumber->data, 16);
        pSerialNumber->length = 16;

        if(pSerialNumber->data == NULL || OpcUa_P_Guid_Create((OpcUa_Guid*)pSerialNumber->data) == NULL)
        {
            uStatus =  OpcUa_Bad;
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }

    /* use the integer passed in - note the API should not be using a 32-bit integer - must fix sometime */
    else if(ASN1_INTEGER_set(X509_get_serialNumber(pCert), a_serialNumber) == 0)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* add key to the request */
    if(X509_set_pubkey(pCert, pSubjectPublicKey) != 1)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(pSubjectPublicKey != OpcUa_Null)
    {
        EVP_PKEY_free(pSubjectPublicKey);
        pSubjectPublicKey = OpcUa_Null;
    }

    /* assign the subject name */
    pSubj = X509_NAME_new();
    if(!pSubj)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* create and add entries to subject name */
    for(i=0; i<a_nameEntriesCount; i++)
    {
        uStatus = OpcUa_P_OpenSSL_X509_Name_AddEntry(&pSubj, a_pNameEntries + i);
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* set subject name in request */
    if(X509_set_subject_name(pCert, pSubj) != 1)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* set name of issuer (CA) */
    if(X509_set_issuer_name(pCert, pSubj) != 1)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(!(X509_gmtime_adj(X509_get_notBefore(pCert), 0)))
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* set ending time of the certificate */
    if(!(X509_gmtime_adj(X509_get_notAfter(pCert), a_validToInSec)))
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* add x509v3 extensions */
    X509V3_set_ctx(&ctx, pCert, pCert, OpcUa_Null, OpcUa_Null, 0);

    for(i=0; i<a_extensionsCount; i++)
    {
        uStatus = OpcUa_P_OpenSSL_X509_AddCustomExtension(&pCert, a_pExtensions+i, &ctx);
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* sign certificate with the CA private key */
    switch(a_signatureHashAlgorithm)
    {
    case OPCUA_P_SHA_160:
        pDigest = EVP_sha1();
        break;
    case OPCUA_P_SHA_224:
        pDigest = EVP_sha224();
        break;
    case OPCUA_P_SHA_256:
        pDigest = EVP_sha256();
        break;
    case OPCUA_P_SHA_384:
        pDigest = EVP_sha384();
        break;
    case OPCUA_P_SHA_512:
        pDigest = EVP_sha512();
        break;
    default:
        uStatus =  OpcUa_BadNotSupported;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(!(X509_sign(pCert, pIssuerPrivateKey, pDigest)))
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(X509_verify(pCert, pIssuerPrivateKey) <= 0)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(pIssuerPrivateKey != OpcUa_Null)
    {
        EVP_PKEY_free(pIssuerPrivateKey);
        pIssuerPrivateKey = OpcUa_Null;
    }

    if(pSubj != OpcUa_Null)
    {
        X509_NAME_free(pSubj);
        pSubj = OpcUa_Null;
    }

    /* prepare container */
    memset(a_pCertificate, 0, sizeof(OpcUa_ByteString));

    /* get required length for conversion target buffer */
    a_pCertificate->Length = i2d_X509(pCert, NULL);

    if(a_pCertificate->Length <= 0)
    {
        /* conversion to DER not possible */
        uStatus = OpcUa_Bad;
    }

    /* allocate conversion target buffer */
    a_pCertificate->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertificate->Length);
    OpcUa_GotoErrorIfAllocFailed(a_pCertificate->Data);

    /* convert into DER */
    a_pCertificate->Length = i2d_X509(pCert, &(a_pCertificate->Data));
    if(a_pCertificate->Length <= 0)
    {
        /* conversion to DER not possible */
        uStatus = OpcUa_Bad;
    }
    else
    {
        /* correct pointer incrementation by i2d_X509() */
        a_pCertificate->Data -= a_pCertificate->Length;
    }

    X509_free(pCert);

OpcUa_ReturnStatusCode;

OpcUa_BeginErrorHandling;

    X509_free(pCert);

    if(pSubjectPublicKey != OpcUa_Null)
    {
        EVP_PKEY_free(pSubjectPublicKey);
    }

    if(pIssuerPrivateKey != OpcUa_Null)
    {
        EVP_PKEY_free(pIssuerPrivateKey);
    }

    if(pSubj != OpcUa_Null)
    {
        X509_NAME_free(pSubj);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_SecureChannel_Renew
 *===========================================================================*/
OpcUa_StatusCode OpcUa_TcpSecureChannel_Renew(  OpcUa_SecureChannel*            a_pSecureChannel,
                                                OpcUa_Handle                    a_hTransportConnection,
                                                OpcUa_ChannelSecurityToken      a_ChannelSecurityToken,
                                                OpcUa_MessageSecurityMode       a_eMessageSecurityMode,
                                                OpcUa_ByteString*               a_pbsClientCertificate,
                                                OpcUa_ByteString*               a_pbsServerCertificate,
                                                OpcUa_SecurityKeyset*           a_pNewReceivingKeyset,
                                                OpcUa_SecurityKeyset*           a_pNewSendingKeyset,
                                                OpcUa_CryptoProvider*           a_pNewCryptoProvider)
{
OpcUa_InitializeStatus(OpcUa_Module_SecureChannel, "Renew");

    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel);
    OpcUa_ReturnErrorIfArgumentNull(a_hTransportConnection);
    OpcUa_ReturnErrorIfArgumentNull(a_pNewCryptoProvider);

    OPCUA_SECURECHANNEL_LOCK(a_pSecureChannel);

    OpcUa_Trace(OPCUA_TRACE_LEVEL_INFO, "OpcUa_TcpSecureChannel_Renew: New token id for channel %u is %u\n", a_pSecureChannel->SecureChannelId, a_ChannelSecurityToken.TokenId);

    if(a_pSecureChannel->TransportConnection != a_hTransportConnection)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadSecureChannelIdInvalid);
    }

    if(a_pSecureChannel->SecureChannelId != a_ChannelSecurityToken.ChannelId)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadSecureChannelIdInvalid);
    }

    /*** TCP SECURECHANNEL ***/
    /* Previous objects will be overwritten by current objects */
    a_pSecureChannel->bCurrentTokenActive                           = OpcUa_False;

    /* set channelSecurityToken members */
    a_pSecureChannel->PreviousChannelSecurityToken.ChannelId        = a_pSecureChannel->CurrentChannelSecurityToken.ChannelId;
    a_pSecureChannel->PreviousChannelSecurityToken.TokenId          = a_pSecureChannel->CurrentChannelSecurityToken.TokenId;
    a_pSecureChannel->PreviousChannelSecurityToken.CreatedAt        = a_pSecureChannel->CurrentChannelSecurityToken.CreatedAt;
    a_pSecureChannel->PreviousChannelSecurityToken.RevisedLifetime  = a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime;

    /* set current channelSecurityToken */
    a_pSecureChannel->CurrentChannelSecurityToken.ChannelId         = a_ChannelSecurityToken.ChannelId;
    a_pSecureChannel->CurrentChannelSecurityToken.TokenId           = a_ChannelSecurityToken.TokenId;
    a_pSecureChannel->CurrentChannelSecurityToken.CreatedAt         = a_ChannelSecurityToken.CreatedAt;
    a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime   = a_ChannelSecurityToken.RevisedLifetime;

    /*** SECURECHANNEL ***/
    a_pSecureChannel->State                                         = OpcUa_SecureChannelState_Opened;
    a_pSecureChannel->MessageSecurityMode                           = a_eMessageSecurityMode;
    a_pSecureChannel->uExpirationCounter                            = (OpcUa_UInt32)(a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime/OPCUA_SECURELISTENER_WATCHDOG_INTERVAL);
    a_pSecureChannel->uOverlapCounter                               = (OpcUa_UInt32)((a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime>>2)/OPCUA_SECURELISTENER_WATCHDOG_INTERVAL);

    /* free old certificate and add new one */
    OpcUa_ByteString_Clear(&a_pSecureChannel->ClientCertificate);

    /* copy client certificate!!! */
    if(a_pbsClientCertificate != OpcUa_Null && a_pbsClientCertificate->Length > 0)
    {
        a_pSecureChannel->ClientCertificate.Data    = (OpcUa_Byte*)OpcUa_Alloc(a_pbsClientCertificate->Length);
        OpcUa_GotoErrorIfAllocFailed(a_pSecureChannel->ClientCertificate.Data);
        a_pSecureChannel->ClientCertificate.Length  = a_pbsClientCertificate->Length;
        OpcUa_MemCpy(   a_pSecureChannel->ClientCertificate.Data,
                        a_pSecureChannel->ClientCertificate.Length,
                        a_pbsClientCertificate->Data,
                        a_pbsClientCertificate->Length);
    }

    /* free old certificate and add new one */
    OpcUa_ByteString_Clear(&a_pSecureChannel->ServerCertificate);

    if(a_pbsServerCertificate != OpcUa_Null && a_pbsServerCertificate->Length > 0)
    {
        a_pSecureChannel->ServerCertificate.Data    = (OpcUa_Byte*)OpcUa_Alloc(a_pbsServerCertificate->Length);
        OpcUa_GotoErrorIfAllocFailed(a_pSecureChannel->ServerCertificate.Data);
        a_pSecureChannel->ServerCertificate.Length  = a_pbsServerCertificate->Length;
        OpcUa_MemCpy(   a_pSecureChannel->ServerCertificate.Data,
                        a_pSecureChannel->ServerCertificate.Length,
                        a_pbsServerCertificate->Data,
                        a_pbsServerCertificate->Length);
    }

    /* delete previous keysets */
    OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pPreviousReceivingKeyset);
    OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pPreviousSendingKeyset);
    OpcUa_Free(a_pSecureChannel->pPreviousReceivingKeyset);
    OpcUa_Free(a_pSecureChannel->pPreviousSendingKeyset);
    a_pSecureChannel->pPreviousReceivingKeyset  = OpcUa_Null;
    a_pSecureChannel->pPreviousSendingKeyset    = OpcUa_Null;

    /* assign current to previous */
    a_pSecureChannel->pPreviousReceivingKeyset                      = a_pSecureChannel->pCurrentReceivingKeyset;
    a_pSecureChannel->pPreviousSendingKeyset                        = a_pSecureChannel->pCurrentSendingKeyset;

    /* delete previous cryptoprovider */
    if(     a_pSecureChannel->pPreviousCryptoProvider != OpcUa_Null
        &&  a_pSecureChannel->pPreviousCryptoProvider != a_pSecureChannel->pCurrentCryptoProvider)
    {
        OPCUA_P_CRYPTOFACTORY_DELETECRYPTOPROVIDER(a_pSecureChannel->pPreviousCryptoProvider);
        OpcUa_Free(a_pSecureChannel->pPreviousCryptoProvider);
        a_pSecureChannel->pPreviousCryptoProvider = OpcUa_Null;
    }
    else
    {
        a_pSecureChannel->pPreviousCryptoProvider = OpcUa_Null;
    }

    /* make current cryptoprovider previous */
    a_pSecureChannel->pPreviousCryptoProvider                       = a_pSecureChannel->pCurrentCryptoProvider;
    a_pSecureChannel->pCurrentCryptoProvider                        = a_pNewCryptoProvider;
    a_pSecureChannel->pCurrentReceivingKeyset                       = a_pNewReceivingKeyset;
    a_pSecureChannel->pCurrentSendingKeyset                         = a_pNewSendingKeyset;

    OPCUA_SECURECHANNEL_UNLOCK(a_pSecureChannel);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_SecurityKeyset_Clear(a_pNewReceivingKeyset);
    OpcUa_SecurityKeyset_Clear(a_pNewSendingKeyset);
    OpcUa_Free(a_pNewReceivingKeyset);
    OpcUa_Free(a_pNewSendingKeyset);

    OPCUA_SECURECHANNEL_UNLOCK(a_pSecureChannel);

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_TcpSecureChannel_Clear
 *===========================================================================*/
OpcUa_StatusCode OpcUa_TcpSecureChannel_Clear(OpcUa_SecureChannel* a_pSecureChannel)
{
OpcUa_InitializeStatus(OpcUa_Module_SecureChannel, "Clear");

    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel);
    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel->Handle);

    OpcUa_String_Clear(&a_pSecureChannel->SecurityPolicyUri);
    OpcUa_String_Clear(&a_pSecureChannel->sPeerInfo);

    OpcUa_Free(a_pSecureChannel->Handle);
    a_pSecureChannel->Handle = OpcUa_Null;

    OpcUa_ByteString_Clear(&a_pSecureChannel->ClientCertificate);

    OpcUa_ByteString_Clear(&a_pSecureChannel->ServerCertificate);

    if(a_pSecureChannel->pCurrentReceivingKeyset != OpcUa_Null)
    {
        OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pCurrentReceivingKeyset);
        OpcUa_Free(a_pSecureChannel->pCurrentReceivingKeyset);
        a_pSecureChannel->pCurrentReceivingKeyset = OpcUa_Null;
    }

    if(a_pSecureChannel->pCurrentSendingKeyset != OpcUa_Null)
    {
        OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pCurrentSendingKeyset);
        OpcUa_Free(a_pSecureChannel->pCurrentSendingKeyset);
        a_pSecureChannel->pCurrentSendingKeyset = OpcUa_Null;
    }

    if(a_pSecureChannel->pPreviousReceivingKeyset != OpcUa_Null)
    {
        OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pPreviousReceivingKeyset);
        OpcUa_Free(a_pSecureChannel->pPreviousReceivingKeyset);
        a_pSecureChannel->pPreviousReceivingKeyset = OpcUa_Null;
    }

    if(a_pSecureChannel->pPreviousSendingKeyset != OpcUa_Null)
    {
        OpcUa_SecurityKeyset_Clear(a_pSecureChannel->pPreviousSendingKeyset);
        OpcUa_Free(a_pSecureChannel->pPreviousSendingKeyset);
        a_pSecureChannel->pPreviousSendingKeyset = OpcUa_Null;
    }

    /* delete both crypto providers */
    if(a_pSecureChannel->pCurrentCryptoProvider != OpcUa_Null)
    {
        if(a_pSecureChannel->pPreviousCryptoProvider == a_pSecureChannel->pCurrentCryptoProvider)
        {
            /* prevent double deletion */
            a_pSecureChannel->pPreviousCryptoProvider = OpcUa_Null;
        }

        OPCUA_P_CRYPTOFACTORY_DELETECRYPTOPROVIDER(a_pSecureChannel->pCurrentCryptoProvider);
        OpcUa_Free(a_pSecureChannel->pCurrentCryptoProvider);
        a_pSecureChannel->pCurrentCryptoProvider = OpcUa_Null;
    }

    if(a_pSecureChannel->pPreviousCryptoProvider != OpcUa_Null)
    {
        OPCUA_P_CRYPTOFACTORY_DELETECRYPTOPROVIDER(a_pSecureChannel->pPreviousCryptoProvider);
        OpcUa_Free(a_pSecureChannel->pPreviousCryptoProvider);
        a_pSecureChannel->pPreviousCryptoProvider = OpcUa_Null;
    }

    if(a_pSecureChannel->pPendingSecureIStream != OpcUa_Null)
    {
        OpcUa_Stream_Close((OpcUa_Stream*)(a_pSecureChannel->pPendingSecureIStream));
        OpcUa_Stream_Delete((OpcUa_Stream**)&(a_pSecureChannel->pPendingSecureIStream));
    }

    while(a_pSecureChannel->pPendingSendBuffers != OpcUa_Null)
    {
        OpcUa_BufferList* pCurrentBuffer = a_pSecureChannel->pPendingSendBuffers;
        a_pSecureChannel->pPendingSendBuffers = pCurrentBuffer->pNext;
        OpcUa_Buffer_Clear(&pCurrentBuffer->Buffer);
        OpcUa_Free(pCurrentBuffer);
    }

    if(a_pSecureChannel->hSyncAccess != OpcUa_Null)
    {
        OPCUA_P_MUTEX_DELETE(&(a_pSecureChannel->hSyncAccess));
        a_pSecureChannel->hSyncAccess = OpcUa_Null;
    }

    if(a_pSecureChannel->hWriteMutex != OpcUa_Null)
    {
        OPCUA_P_MUTEX_DELETE(&(a_pSecureChannel->hWriteMutex));
        a_pSecureChannel->hWriteMutex = OpcUa_Null;
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_SecureChannel_Open
 *===========================================================================*/
OpcUa_StatusCode OpcUa_TcpSecureChannel_Open(   OpcUa_SecureChannel*            a_pSecureChannel,
                                                OpcUa_Handle                    a_hTransportConnection,
                                                OpcUa_ChannelSecurityToken      a_channelSecurityToken,
                                                OpcUa_MessageSecurityMode       a_messageSecurityMode,
                                                OpcUa_ByteString*               a_pbsClientCertificate,
                                                OpcUa_ByteString*               a_pbsServerCertificate,
                                                OpcUa_SecurityKeyset*           a_pReceivingKeyset,
                                                OpcUa_SecurityKeyset*           a_pSendingKeyset,
                                                OpcUa_CryptoProvider*           a_pCryptoProvider)
{
OpcUa_InitializeStatus(OpcUa_Module_SecureChannel, "Open");

    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel);
    OpcUa_ReturnErrorIfArgumentNull(a_hTransportConnection);
    OpcUa_ReturnErrorIfArgumentNull(a_pCryptoProvider);

    OPCUA_SECURECHANNEL_LOCK(a_pSecureChannel);

    if(a_pSecureChannel->SecureChannelId != a_channelSecurityToken.ChannelId)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadSecureChannelIdInvalid);
    }

    a_pSecureChannel->bCurrentTokenActive                           = OpcUa_True;

    /*** TCP SECURECHANNEL ***/
    a_pSecureChannel->CurrentChannelSecurityToken.ChannelId         = a_channelSecurityToken.ChannelId;
    a_pSecureChannel->CurrentChannelSecurityToken.TokenId           = a_channelSecurityToken.TokenId;
    a_pSecureChannel->CurrentChannelSecurityToken.CreatedAt         = a_channelSecurityToken.CreatedAt;
    a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime   = a_channelSecurityToken.RevisedLifetime;

    /*** SECURECHANNEL ***/
    a_pSecureChannel->State                                         = OpcUa_SecureChannelState_Opened;
    a_pSecureChannel->TransportConnection                           = a_hTransportConnection;
    a_pSecureChannel->MessageSecurityMode                           = a_messageSecurityMode;
    a_pSecureChannel->uExpirationCounter                            = (OpcUa_UInt32)(a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime/OPCUA_SECURELISTENER_WATCHDOG_INTERVAL);
    a_pSecureChannel->uOverlapCounter                               = (OpcUa_UInt32)((a_pSecureChannel->CurrentChannelSecurityToken.RevisedLifetime>>2)/OPCUA_SECURELISTENER_WATCHDOG_INTERVAL);

    /* copy client certificate */
    if(a_pbsClientCertificate != OpcUa_Null && a_pbsClientCertificate->Length > 0)
    {
        a_pSecureChannel->ClientCertificate.Data    = (OpcUa_Byte *)OpcUa_Alloc(a_pbsClientCertificate->Length);
        OpcUa_GotoErrorIfAllocFailed(a_pSecureChannel->ClientCertificate.Data);
        a_pSecureChannel->ClientCertificate.Length  = a_pbsClientCertificate->Length;
        OpcUa_MemCpy(   a_pSecureChannel->ClientCertificate.Data,
                        a_pSecureChannel->ClientCertificate.Length,
                        a_pbsClientCertificate->Data,
                        a_pbsClientCertificate->Length);
    }
    else
    {
        OpcUa_ByteString_Initialize(&a_pSecureChannel->ClientCertificate);
    }

    if(a_pbsServerCertificate != OpcUa_Null && a_pbsServerCertificate->Length > 0)
    {
        a_pSecureChannel->ServerCertificate.Data    = (OpcUa_Byte*)OpcUa_Alloc(a_pbsServerCertificate->Length);
        OpcUa_GotoErrorIfAllocFailed(a_pSecureChannel->ServerCertificate.Data);
        a_pSecureChannel->ServerCertificate.Length  = a_pbsServerCertificate->Length;

        OpcUa_MemCpy(   a_pSecureChannel->ServerCertificate.Data,
                        a_pSecureChannel->ServerCertificate.Length,
                        a_pbsServerCertificate->Data,
                        a_pbsServerCertificate->Length);
    }
    else
    {
        OpcUa_ByteString_Initialize(&a_pSecureChannel->ServerCertificate);
    }

    a_pSecureChannel->pCurrentReceivingKeyset   = a_pReceivingKeyset;
    a_pSecureChannel->pCurrentSendingKeyset     = a_pSendingKeyset;
    a_pSecureChannel->pCurrentCryptoProvider    = a_pCryptoProvider;

    OPCUA_SECURECHANNEL_UNLOCK(a_pSecureChannel);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_SecurityKeyset_Clear(a_pReceivingKeyset);
    OpcUa_SecurityKeyset_Clear(a_pSendingKeyset);
    OpcUa_Free(a_pReceivingKeyset);
    OpcUa_Free(a_pSendingKeyset);

    OPCUA_SECURECHANNEL_UNLOCK(a_pSecureChannel);

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_TcpSecureChannel_GetSecuritySet
 *===========================================================================*/
OpcUa_StatusCode OpcUa_TcpSecureChannel_GetSecuritySet( OpcUa_SecureChannel*    a_pSecureChannel,
                                                        OpcUa_UInt32            a_uTokenId,
                                                        OpcUa_SecurityKeyset**  a_ppReceivingKeyset,
                                                        OpcUa_SecurityKeyset**  a_ppSendingKeyset,
                                                        OpcUa_CryptoProvider**  a_ppCryptoProvider)
{
OpcUa_InitializeStatus(OpcUa_Module_SecureChannel, "GetSecuritySet");

    OpcUa_ReturnErrorIfArgumentNull(a_pSecureChannel);

    OpcUa_Trace(OPCUA_TRACE_LEVEL_DEBUG, "GetSecurityKeyset: Keysets for token id %u requested.\n", a_uTokenId);

    OPCUA_SECURECHANNEL_LOCK(a_pSecureChannel);

    if(a_pSecureChannel->CurrentChannelSecurityToken.TokenId == a_uTokenId)
    {
        /* immediately activate the new keyset */
        a_pSecureChannel->bCurrentTokenActive = OpcUa_True;

        if(a_ppReceivingKeyset != OpcUa_Null)
        {
            *a_ppReceivingKeyset = a_pSecureChannel->pCurrentReceivingKeyset;
        }

        if(a_ppSendingKeyset != OpcUa_Null)
        {
            *a_ppSendingKeyset = a_pSecureChannel->pCurrentSendingKeyset;
        }

        if(a_ppCryptoProvider != OpcUa_Null)
        {
            *a_ppCryptoProvider = a_pSecureChannel->pCurrentCryptoProvider;
        }
    }
    else if(a_pSecureChannel->PreviousChannelSecurityToken.TokenId == a_uTokenId)
    {
        if(a_ppReceivingKeyset != OpcUa_Null)
        {
            *a_ppReceivingKeyset = a_pSecureChannel->pPreviousReceivingKeyset;
        }

        if(a_ppSendingKeyset != OpcUa_Null)
        {
            *a_ppSendingKeyset = a_pSecureChannel->pPreviousSendingKeyset;
        }

        if(a_ppCryptoProvider != OpcUa_Null)
        {
            *a_ppCryptoProvider = a_pSecureChannel->pPreviousCryptoProvider;
        }
    }
    else
    {
        uStatus = OpcUa_BadSecureChannelTokenUnknown;
        OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "GetSecurityKeyset: Token id %u at secure channel %u invalid!\n", a_uTokenId, a_pSecureChannel->SecureChannelId);
        OPCUA_SECURECHANNEL_UNLOCK(a_pSecureChannel);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
Exemple #14
0
/*============================================================================
 * OpcUa_P_ParseUrl
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_ParseUrl(  OpcUa_StringA   a_psUrl,
                                    OpcUa_StringA*  a_psIpAddress,
                                    OpcUa_UInt16*   a_puPort)
{
    OpcUa_StringA       sHostName         = OpcUa_Null;
    OpcUa_UInt32        uHostNameLength   = 0;

    OpcUa_CharA*        sPort             = OpcUa_Null;

    OpcUa_CharA*        pcCursor;

    OpcUa_Int           nIndex1           = 0;
    OpcUa_Int           nIpStart;

    struct addrinfo*    pAddrInfo         = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_Utilities, "P_ParseUrl");

    OpcUa_ReturnErrorIfArgumentNull(a_psUrl);
    OpcUa_ReturnErrorIfArgumentNull(a_psIpAddress);
    OpcUa_ReturnErrorIfArgumentNull(a_puPort);


    *a_psIpAddress = OpcUa_Null;

    /* check for // (end of protocol header) */
    pcCursor = strstr(a_psUrl, "//");

    if(pcCursor != OpcUa_Null)
    {
        /* begin of host address */
        pcCursor += 2;
        nIndex1 = (OpcUa_Int)(pcCursor - a_psUrl);
    }

    /* skip protocol prefix and store beginning of ip adress */
    nIpStart = nIndex1;

    /* skip host address (IPv6 address can contain colons!) */
    while(a_psUrl[nIndex1] != '/' && a_psUrl[nIndex1] != 0)
    {
        if(a_psUrl[nIndex1] == ':')
        {
            sPort = &a_psUrl[nIndex1 + 1];
            uHostNameLength = nIndex1 - nIpStart;
        }
        /* handle "opc.tcp://[::1]:4880/" */
        if(a_psUrl[nIndex1] == ']' && sPort != OpcUa_Null && a_psUrl[nIpStart] == '[')
        {
            nIpStart++;
            uHostNameLength = nIndex1 - nIpStart;
            sPort = OpcUa_Null;
            if(a_psUrl[nIndex1 + 1] == ':')
            {
                sPort = &a_psUrl[nIndex1 + 2];
            }
            break;
        }
        nIndex1++;
    }

    if(uHostNameLength == 0)
    {
        uHostNameLength = nIndex1 - nIpStart;
    }

    /* scan port */
    if(sPort != OpcUa_Null)
    {
        /* convert port */
        *a_puPort = (OpcUa_UInt16)OpcUa_P_CharAToInt(sPort);
    }
    else
    {
        /* return default port */
        *a_puPort = OPCUA_TCP_DEFAULT_PORT;
    }

    sHostName = (OpcUa_StringA)OpcUa_P_Memory_Alloc(uHostNameLength + 1);

    if(sHostName == NULL)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadOutOfMemory);
    }

    memcpy(sHostName, &a_psUrl[nIpStart], uHostNameLength);
    sHostName[uHostNameLength] = '\0';

    if(getaddrinfo(sHostName, NULL, NULL, &pAddrInfo))
    {
        /* hostname could not be resolved */
        pAddrInfo = NULL;
        OpcUa_GotoErrorWithStatus(OpcUa_BadHostUnknown);
    }

    if(pAddrInfo->ai_family == AF_INET)
    {
        struct sockaddr_in* pAddr = (struct sockaddr_in*)pAddrInfo->ai_addr;
        OpcUa_P_Memory_Free(sHostName);
        sHostName = OpcUa_P_Memory_Alloc(INET_ADDRSTRLEN);
        OpcUa_GotoErrorIfAllocFailed(sHostName);
        if(inet_ntop(AF_INET, (void*)&pAddr->sin_addr,
                     sHostName, INET_ADDRSTRLEN) == NULL)
        {
            OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError);
        }
    }
    else if(pAddrInfo->ai_family == AF_INET6)
    {
        struct sockaddr_in6* pAddr = (struct sockaddr_in6*)pAddrInfo->ai_addr;
        OpcUa_P_Memory_Free(sHostName);
        sHostName = OpcUa_P_Memory_Alloc(INET6_ADDRSTRLEN);
        OpcUa_GotoErrorIfAllocFailed(sHostName);
        if(inet_ntop(AF_INET6, (void*)&pAddr->sin6_addr,
                     sHostName, INET6_ADDRSTRLEN) == NULL)
        {
            OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError);
        }
        if(pAddr->sin6_scope_id)
        {
            char *pScopeAddress = OpcUa_P_Memory_Alloc(strlen(sHostName) + 12);
            OpcUa_GotoErrorIfAllocFailed(pScopeAddress);
            sprintf(pScopeAddress, "%s%%%u", sHostName, pAddr->sin6_scope_id);
            OpcUa_P_Memory_Free(sHostName);
            sHostName = pScopeAddress;
        }
    }
    else
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError);
    }

    *a_psIpAddress = sHostName;
    freeaddrinfo(pAddrInfo);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(sHostName != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(sHostName);
    }

    if(pAddrInfo != NULL)
    {
        freeaddrinfo(pAddrInfo);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * Create a client socket
 *===========================================================================*/
OpcUa_StatusCode OPCUA_DLLCALL OpcUa_P_SocketManager_CreateClient(  OpcUa_SocketManager         a_hSocketManager,
                                                                    OpcUa_StringA               a_sRemoteAddress,
                                                                    OpcUa_UInt16                a_uLocalPort,
                                                                    OpcUa_Socket_EventCallback  a_pfnSocketCallBack,
                                                                    OpcUa_Void*                 a_pCallbackData,
                                                                    OpcUa_Socket*               a_pSocket)
{
    OpcUa_InternalSocket*        pNewClientSocket       = OpcUa_Null;
    OpcUa_InternalSocketManager* pInternalSocketManager = OpcUa_Null;
    OpcUa_UInt16                 uPort                  = 0;
    OpcUa_StringA                sRemoteAdress          = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_Socket, "CreateClient");

#if !OPCUA_MULTITHREADED
    if(a_hSocketManager == OpcUa_Null)
    {
        a_hSocketManager = OpcUa_Socket_g_SocketManager;
    }
#endif

    OpcUa_ReturnErrorIfArgumentNull(a_hSocketManager);
    OpcUa_ReturnErrorIfArgumentNull(a_pSocket);
    OpcUa_ReturnErrorIfArgumentNull(a_sRemoteAddress);

    /* parse address */
    uStatus = OpcUa_P_ParseUrl( a_sRemoteAddress,
                                &sRemoteAdress,
                                &uPort);
    OpcUa_ReturnErrorIfBad(uStatus);

    pInternalSocketManager = (OpcUa_InternalSocketManager*)a_hSocketManager;

    pNewClientSocket = (OpcUa_InternalSocket*)OpcUa_SocketManager_FindFreeSocket(   (OpcUa_SocketManager)pInternalSocketManager,
                                                                                    OpcUa_False);
    if (pNewClientSocket == OpcUa_Null)
    {
        OpcUa_P_Memory_Free(sRemoteAdress);
        uStatus = OpcUa_BadMaxConnectionsReached; /* no socket left in the list. */
        goto Error;
    }

    /* Create client socket. */
    pNewClientSocket->rawSocket = OpcUa_P_Socket_CreateClient(  a_uLocalPort,
                                                                uPort,
                                                                sRemoteAdress,
                                                                &uStatus);

    OpcUa_P_Memory_Free(sRemoteAdress);

    OpcUa_GotoErrorIfTrue(  pNewClientSocket->rawSocket == (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID,
                            OpcUa_BadCommunicationError);

    pNewClientSocket->pfnEventCallback       = a_pfnSocketCallBack;
    pNewClientSocket->pvUserData             = a_pCallbackData;
    pNewClientSocket->Flags.bOwnThread       = OpcUa_False;
    pNewClientSocket->Flags.EventMask        = OPCUA_SOCKET_READ_EVENT
                                             | OPCUA_SOCKET_EXCEPT_EVENT
                                             | OPCUA_SOCKET_CONNECT_EVENT
                                             | OPCUA_SOCKET_TIMEOUT_EVENT;

    OPCUA_SOCKET_SETVALID(pNewClientSocket);

    /* return the new client socket */
    *a_pSocket = pNewClientSocket;

    /* break loop to add new socket into eventing */
    uStatus = OpcUa_P_SocketManager_InterruptLoop(  a_hSocketManager,
                                                    OPCUA_SOCKET_RENEWLOOP_EVENT,
                                                    OpcUa_False);
    OpcUa_GotoErrorIfBad(uStatus);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pNewClientSocket != OpcUa_Null)
    {
        if(pNewClientSocket->rawSocket != (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID)
        {
            OpcUa_P_RawSocket_Close(pNewClientSocket->rawSocket);
            pNewClientSocket->rawSocket = (OpcUa_RawSocket)OPCUA_P_SOCKET_INVALID;
        }
        OPCUA_SOCKET_INVALIDATE(pNewClientSocket);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_X509_LoadFromFile
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_X509_LoadFromFile(
    OpcUa_StringA               a_fileName,
    OpcUa_P_FileFormat          a_fileFormat,
    OpcUa_StringA               a_sPassword,        /* optional: just for OpcUa_PKCS12 */
    OpcUa_ByteString*           a_pCertificate)
{
    BIO*            pCertFile       = OpcUa_Null;
    X509*           pCertX509       = OpcUa_Null;
    PKCS12*         pPKCS12Cert     = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_LoadFromFile");

    /* check filename */
    if(OpcUa_P_String_strlen(a_fileName) < 1)
    {
        uStatus = OpcUa_BadInvalidArgument;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    /* import certificate from file by the given encoding type */
    pCertFile = BIO_new_file((const char*)a_fileName, "r");
    OpcUa_ReturnErrorIfArgumentNull(pCertFile);

    switch(a_fileFormat)
    {
    case OpcUa_Crypto_Encoding_DER:
        {

            pCertX509 = d2i_X509_bio(pCertFile,      /* sourcefile */
                                     (X509**)NULL);  /* target (if preallocated) */
            break;
        }
    case OpcUa_Crypto_Encoding_PEM:
        {

            pCertX509 = PEM_read_bio_X509(  pCertFile,          /* sourcefile */
                                            (X509**)OpcUa_Null, /* target (if preallocated) */
                                            OpcUa_Null,         /* password callback function */
                                            OpcUa_Null);        /* passphrase or callback data */
            break;
        }
    case OpcUa_Crypto_Encoding_PKCS12:
        {
            d2i_PKCS12_bio(pCertFile, &pPKCS12Cert);

            PKCS12_parse(pPKCS12Cert, a_sPassword, OpcUa_Null, &pCertX509, OpcUa_Null);

            if(pPKCS12Cert != OpcUa_Null)
            {
                PKCS12_free(pPKCS12Cert);
                /*OPENSSL_free(pPKCS12Cert);*/
            }

            break;
        }
    default:
        {
            BIO_free(pCertFile);
            return OpcUa_BadNotSupported;
        }
    }

    BIO_free(pCertFile);
    pCertFile = OpcUa_Null;

    if(pCertX509 == OpcUa_Null)
    {
        /* error in OpenSSL - maybe certificate file was corrupt */
        return OpcUa_Bad;
    }

    /* prepare container */
    memset(a_pCertificate, 0, sizeof(OpcUa_ByteString));

    /* get required length for conversion target buffer */
    a_pCertificate->Length = i2d_X509(  pCertX509,
                                            NULL);

    if(a_pCertificate->Length <= 0)
    {
        /* conversion to DER not possible */
        uStatus = OpcUa_Bad;
    }

    /* allocate conversion target buffer */
    a_pCertificate->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertificate->Length);
    OpcUa_GotoErrorIfAllocFailed(a_pCertificate->Data);

    /* convert into DER */
    a_pCertificate->Length = i2d_X509(  pCertX509,
                                            &(a_pCertificate->Data));
    if(a_pCertificate->Length <= 0)
    {
        /* conversion to DER not possible */
        uStatus = OpcUa_Bad;
    }
    else
    {
        /* correct pointer incrementation by i2d_X509() */
        a_pCertificate->Data -= a_pCertificate->Length;
    }

    X509_free(pCertX509);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pCertX509 != OpcUa_Null)
    {
        X509_free(pCertX509);
    }

    if(pPKCS12Cert != OpcUa_Null)
    {
        OPENSSL_free(pPKCS12Cert);
    }

    if(a_pCertificate->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pCertificate->Data);
        a_pCertificate->Data = OpcUa_Null;
    }

    if(pCertFile != OpcUa_Null)
    {
        BIO_free(pCertFile);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_CertificateStore_Open
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_OpenCertificateStore(
    OpcUa_PKIProvider*          a_pProvider,
    OpcUa_Void**                a_ppCertificateStore)           /* type depends on store implementation */
{
    OpcUa_P_OpenSSL_CertificateStore_Config*    pCertificateStoreCfg;
    X509_STORE*         pStore;
    X509_LOOKUP*        pLookup;
    char                CertFile[MAX_PATH];
    struct dirent **dirlist = NULL;
    int numCertificates = 0, i;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_OpenCertificateStore");

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle);
    OpcUa_ReturnErrorIfArgumentNull(a_ppCertificateStore);

    *a_ppCertificateStore = OpcUa_Null;

    pCertificateStoreCfg = (OpcUa_P_OpenSSL_CertificateStore_Config*)a_pProvider->Handle;

    if(!(*a_ppCertificateStore = pStore = X509_STORE_new()))
    {
        OpcUa_GotoErrorWithStatus(OpcUa_Bad);
    }

    X509_STORE_set_verify_cb_func(pStore, OpcUa_P_OpenSSL_CertificateStore_Verify_Callback);

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_USE_DEFAULT_CERT_CRL_LOOKUP_METHOD)
    {
        if(X509_STORE_set_default_paths(pStore) != 1)
        {
            OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_STORE_set_default_paths!\n");
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
    }

    if(!(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_DONT_ADD_TRUST_LIST_TO_ROOT_CERTIFICATES))
    {
        if(pCertificateStoreCfg->CertificateTrustListLocation == OpcUa_Null || pCertificateStoreCfg->CertificateTrustListLocation[0] == '\0')
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }

        /* how to search for certificate & CRLs */
        if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())))
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }

        /* how to search for certificate & CRLs */
        numCertificates = scandir(pCertificateStoreCfg->CertificateTrustListLocation, &dirlist, certificate_filter_der, alphasort);
        for (i=0; i<numCertificates; i++)
        {
            uStatus = OpcUa_P_OpenSSL_BuildFullPath(pCertificateStoreCfg->CertificateTrustListLocation, dirlist[i]->d_name, MAX_PATH, CertFile);
            OpcUa_GotoErrorIfBad(uStatus);

            /* add CACertificate lookup */
            if(X509_LOOKUP_load_file(pLookup, CertFile, X509_FILETYPE_ASN1) != 1) /*DER encoded*/
            {
                OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_LOOKUP_load_file: skipping %s\n", CertFile);
            }
        }
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
        dirlist = NULL;
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_ADD_UNTRUSTED_LIST_TO_ROOT_CERTIFICATES)
    {
        if(pCertificateStoreCfg->CertificateUntrustedListLocation == OpcUa_Null || pCertificateStoreCfg->CertificateUntrustedListLocation[0] == '\0')
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }

        if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_UNTRUSTED_LIST_IS_INDEX)
        {
            /* how to search for certificate */
            if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir())))
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }

            /* add hash lookup */
            if(X509_LOOKUP_add_dir(pLookup, pCertificateStoreCfg->CertificateUntrustedListLocation, X509_FILETYPE_ASN1) != 1) /*DER encoded*/
            {
                OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_LOOKUP_add_dir!\n");
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }
        }
        else
        {
            /* how to search for certificate & CRLs */
            if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())))
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }

            numCertificates = scandir(pCertificateStoreCfg->CertificateUntrustedListLocation, &dirlist, certificate_filter_der, alphasort);
            for (i=0; i<numCertificates; i++)
            {
                uStatus = OpcUa_P_OpenSSL_BuildFullPath(pCertificateStoreCfg->CertificateUntrustedListLocation, dirlist[i]->d_name, MAX_PATH, CertFile);
                OpcUa_GotoErrorIfBad(uStatus);

                /* add CACertificate lookup */
                if(X509_LOOKUP_load_file(pLookup, CertFile, X509_FILETYPE_ASN1) != 1) /*DER encoded*/
                {
                    OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_LOOKUP_load_file: skipping %s\n", CertFile);
                }
            }
            for (i=0; i<numCertificates; i++)
            {
                free(dirlist[i]);
            }
            free(dirlist);
            dirlist = NULL;
        }
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL)
    {
        if(pCertificateStoreCfg->CertificateRevocationListLocation == OpcUa_Null || pCertificateStoreCfg->CertificateRevocationListLocation[0] == '\0')
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }

        if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_REVOCATION_LIST_IS_INDEX)
        {
            /* how to search for certificate & CRLs */
            if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir())))
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }

            /* add CRL lookup */
            if(X509_LOOKUP_add_dir(pLookup, pCertificateStoreCfg->CertificateRevocationListLocation, X509_FILETYPE_PEM) != 1) /*PEM encoded*/
            {
                OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_LOOKUP_add_dir!\n");
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }
        }
        else if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_REVOCATION_LIST_IS_CONCATENATED_PEM_FILE)
        {
            /* how to search for certificate & CRLs */
            if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())))
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }

            /* add CRL lookup */
            if(X509_load_crl_file(pLookup, pCertificateStoreCfg->CertificateRevocationListLocation, X509_FILETYPE_PEM) != 1) /*PEM encoded*/
            {
                OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_load_crl_file!\n");
            }
        }
        else
        {
            /* how to search for certificate & CRLs */
            if(!(pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())))
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }

            numCertificates = scandir(pCertificateStoreCfg->CertificateRevocationListLocation, &dirlist, certificate_filter_crl, alphasort);
            for (i=0; i<numCertificates; i++)
            {
                uStatus = OpcUa_P_OpenSSL_BuildFullPath(pCertificateStoreCfg->CertificateRevocationListLocation, dirlist[i]->d_name, MAX_PATH, CertFile);
                OpcUa_GotoErrorIfBad(uStatus);

                if(X509_load_crl_file(pLookup, CertFile, X509_FILETYPE_PEM) != 1) /*PEM encoded*/
                {
                    OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "error at X509_load_crl_file: skipping %s\n", CertFile);
                }
            }
            for (i=0; i<numCertificates; i++)
            {
                free(dirlist[i]);
            }
            free(dirlist);
            dirlist = NULL;
        }

        if((pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL) == OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ALL)
        {
            /* set the flags of the store so that CRLs are consulted */
            if(X509_STORE_set_flags(pStore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) != 1)
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }
        }
        else if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_REVOCATION_ONLY_LEAF)
        {
            /* set the flags of the store so that CRLs are consulted */
            if(X509_STORE_set_flags(pStore, X509_V_FLAG_CRL_CHECK) != 1)
            {
                OpcUa_GotoErrorWithStatus(OpcUa_Bad);
            }
        }
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_CHECK_SELF_SIGNED_SIGNATURE)
    {
        /* set the flags of the store so that CRLs are consulted */
        if(X509_STORE_set_flags(pStore, X509_V_FLAG_CHECK_SS_SIGNATURE) != 1)
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
    }

    if(pCertificateStoreCfg->Flags & OPCUA_P_PKI_OPENSSL_ALLOW_PROXY_CERTIFICATES)
    {
        /* set the flags of the store so that CRLs are consulted */
        if(X509_STORE_set_flags(pStore, X509_V_FLAG_ALLOW_PROXY_CERTS) != 1)
        {
            OpcUa_GotoErrorWithStatus(OpcUa_Bad);
        }
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(dirlist != NULL)
    {
        for (i=0; i<numCertificates; i++)
        {
            free(dirlist[i]);
        }
        free(dirlist);
    }

    if(*a_ppCertificateStore != OpcUa_Null)
    {
        X509_STORE_free((X509_STORE*)*a_ppCertificateStore);
        *a_ppCertificateStore = OpcUa_Null;
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_X509_GetPublicKey
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_X509_GetPublicKey(
    OpcUa_CryptoProvider*       a_pProvider,
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_StringA               a_password,             /* this could be optional */
    OpcUa_Key*                  a_pPublicKey)
{
    EVP_PKEY*           pPublicKey      = OpcUa_Null;
    RSA*                pRsaPublicKey   = OpcUa_Null;
    X509*               pCertificate    = OpcUa_Null;
    OpcUa_Byte*         pBuffer         = OpcUa_Null;
    BIO*                bi;

    OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_GetPublicKey");

    OpcUa_ReferenceParameter(a_password);

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate->Data);
    OpcUa_ReturnErrorIfArgumentNull(a_pPublicKey);

    bi = BIO_new(BIO_s_mem());
    BIO_write(bi, a_pCertificate->Data, a_pCertificate->Length);

    pCertificate = d2i_X509_bio(bi, NULL);

    BIO_free(bi);

    if(pCertificate == OpcUa_Null)
    {
        return OpcUa_BadCertificateInvalid;
    }

    /* get EVP_PKEY from X509 certificate */
    pPublicKey = X509_get_pubkey(pCertificate);
    if(pPublicKey == OpcUa_Null)
    {
        X509_free(pCertificate);
        return OpcUa_BadCertificateInvalid;
    }

    /* free X509 certificate, since not needed anymore */
    X509_free(pCertificate);

    switch(EVP_PKEY_type(pPublicKey->type))
    {
    case EVP_PKEY_RSA:

        /* allocate memory for RSA key */

        /* get RSA public key from EVP_PKEY */
        pRsaPublicKey = EVP_PKEY_get1_RSA(pPublicKey);

        /* allocate memory for DER encoded bytestring */
        a_pPublicKey->Key.Length = i2d_RSAPublicKey(pRsaPublicKey, OpcUa_Null);

        if(a_pPublicKey->Key.Data == OpcUa_Null)
        {
            RSA_free(pRsaPublicKey);
            pRsaPublicKey = OpcUa_Null;

            EVP_PKEY_free(pPublicKey);
            pPublicKey = OpcUa_Null;

            OpcUa_ReturnStatusCode;
        }

        /* convert RSA key to DER encoded bytestring */
        pBuffer = a_pPublicKey->Key.Data;
        a_pPublicKey->Key.Length = i2d_RSAPublicKey(pRsaPublicKey, &pBuffer);
        a_pPublicKey->Type = OpcUa_Crypto_KeyType_Rsa_Public;

        /* free memory for RSA key */
        RSA_free(pRsaPublicKey);
        pRsaPublicKey = OpcUa_Null;

        break;

    case EVP_PKEY_EC:
    case EVP_PKEY_DSA:
    case EVP_PKEY_DH:
    default:
        OpcUa_GotoErrorWithStatus(OpcUa_BadNotSupported);
    }

    /*** clean up ***/
    EVP_PKEY_free(pPublicKey);
    pPublicKey = OpcUa_Null;

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    EVP_PKEY_free(pPublicKey);
    pPublicKey = OpcUa_Null;

OpcUa_FinishErrorHandling;
}
/*
    ToDo:   Create Access to OpenSSL certificate store
            => Only API to In-Memory-Store is available for version 0.9.8x
            => Wait until Directory- and/or File-Store is available
*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_SaveCertificate(
    OpcUa_PKIProvider*          a_pProvider,
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_Void*                 a_pCertificateStore,
    OpcUa_Void*                 a_pSaveHandle)      /* Index or number within store/destination filepath */
{
    X509*                                       pX509Certificate        = OpcUa_Null;
    FILE*                                       pCertificateFile        = OpcUa_Null;

    const unsigned char*                        p;

    OpcUa_UInt32                                i;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_SaveCertificate");


    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_pProvider->Handle);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);
    OpcUa_ReturnErrorIfArgumentNull(a_pCertificateStore);
    OpcUa_ReturnErrorIfArgumentNull(a_pSaveHandle);

    /* save DER certificate */
    pCertificateFile = fopen((const char*)a_pSaveHandle, "w");

    /* check for valid file handle */
    OpcUa_GotoErrorIfTrue((pCertificateFile == OpcUa_Null), OpcUa_BadInvalidArgument);

    /* convert openssl X509 certificate to DER encoded bytestring certificate */
    p = a_pCertificate->Data;
    while (p < a_pCertificate->Data + a_pCertificate->Length)
    {
        if(!(pX509Certificate = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Data + a_pCertificate->Length - p)))
        {
            fclose(pCertificateFile);
            uStatus = OpcUa_Bad;
            OpcUa_GotoErrorIfBad(uStatus);
        }

        i = i2d_X509_fp(pCertificateFile, pX509Certificate);

        if(i < 1)
        {
            fclose(pCertificateFile);
            uStatus =  OpcUa_Bad;
            OpcUa_GotoErrorIfBad(uStatus);
        }

        X509_free(pX509Certificate);
        pX509Certificate = OpcUa_Null;
    }

    if(fclose(pCertificateFile) != 0)
    {
        uStatus =  OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if (pX509Certificate != OpcUa_Null)
    {
        X509_free(pX509Certificate);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_X509_GetPrivateKey
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_X509_GetPrivateKey(
    OpcUa_CryptoProvider*       a_pProvider,
    OpcUa_StringA               a_certificateFileName,
    OpcUa_StringA               a_password,             /* this is optional */
    OpcUa_Key*                  a_pPrivateKey)
{
    BIO*            pCertFile       = OpcUa_Null;
    PKCS12*         pPKCS12Cert     = OpcUa_Null;
    EVP_PKEY*       pPrivateKey     = OpcUa_Null;
    RSA*            pRsaPrivateKey  = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "X509_GetPrivateKey");

    OpcUa_ReferenceParameter(a_pProvider);

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_certificateFileName);
    OpcUa_ReturnErrorIfArgumentNull(a_pPrivateKey);

    /* import certificate from file by the given encoding type */
    pCertFile = BIO_new_file((const char*)a_certificateFileName, "r");
    OpcUa_ReturnErrorIfArgumentNull(pCertFile);

    /* convert certificate file handle to PKCS12 structure */
    d2i_PKCS12_bio(pCertFile, &pPKCS12Cert);

    /* close certificat file handle */
    BIO_free(pCertFile);

    if(pPKCS12Cert != OpcUa_Null)
    {
        /* get the private key from the PKCS12 structure*/
        PKCS12_parse(pPKCS12Cert, a_password, &pPrivateKey, OpcUa_Null, OpcUa_Null);
    }
    else
    {
        uStatus = OpcUa_Bad;
        OpcUa_ReturnStatusCode;
    }

    if(pPKCS12Cert != OpcUa_Null)
    {
        PKCS12_free(pPKCS12Cert);
        pPKCS12Cert = OpcUa_Null;
    }

    switch(EVP_PKEY_type(pPrivateKey->type))
    {
    case EVP_PKEY_RSA:
        {
            /* convert to intermediary openssl struct */
            pRsaPrivateKey = EVP_PKEY_get1_RSA(pPrivateKey);
            EVP_PKEY_free(pPrivateKey);
            OpcUa_GotoErrorIfNull(pRsaPrivateKey, OpcUa_Bad);

            /* get required length */
            a_pPrivateKey->Key.Length = i2d_RSAPrivateKey(pRsaPrivateKey, OpcUa_Null);
            OpcUa_GotoErrorIfTrue(a_pPrivateKey->Key.Length <= 0, OpcUa_Bad);

            if(a_pPrivateKey->Key.Data == OpcUa_Null)
            {
                OpcUa_ReturnStatusCode;
            }

            /* do real conversion */
            a_pPrivateKey->Key.Length = i2d_RSAPrivateKey(  pRsaPrivateKey,
                                                            &a_pPrivateKey->Key.Data);
            OpcUa_GotoErrorIfTrue(a_pPrivateKey->Key.Length <= 0, OpcUa_Bad);

            if(pRsaPrivateKey != OpcUa_Null)
            {
                RSA_free(pRsaPrivateKey);
                pRsaPrivateKey = OpcUa_Null;
            }

            /* correct buffer pointer */
            a_pPrivateKey->Key.Data -= a_pPrivateKey->Key.Length;

            a_pPrivateKey->Type = OpcUa_Crypto_KeyType_Rsa_Private;

            break;
        }
    case EVP_PKEY_EC:
    case EVP_PKEY_DSA:
    case EVP_PKEY_DH:
    default:
        {
            uStatus =  OpcUa_BadNotSupported;
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pRsaPrivateKey != OpcUa_Null)
    {
        RSA_free(pRsaPrivateKey);
    }

    if(pPrivateKey != OpcUa_Null)
    {
        EVP_PKEY_free(pPrivateKey);
    }

OpcUa_FinishErrorHandling;
}
/**
  @brief Extracts data from a certificate store object.

  @param pCertificate          [in] The certificate to examine.
  @param pIssuer               [out, optional] The issuer name of the certificate.
  @param pSubject              [out, optional] The subject name of the certificate.
  @param pSubjectUri           [out, optional] The subject's URI of the certificate.
  @param pSubjectIP            [out, optional] The subject's IP of the certificate.
  @param pSubjectDNS           [out, optional] The subject's DNS name of the certificate.
  @param pCertThumbprint       [out, optional] The thumbprint of the certificate.
  @param pSubjectHash          [out, optional] The hash code of the certificate.
  @param pCertRawLength        [out, optional] The length of the DER encoded data.
                               can be smaller than the total length of pCertificate in case of chain certificate or garbage follow.
*/
OpcUa_StatusCode OpcUa_P_OpenSSL_PKI_ExtractCertificateData(
    OpcUa_ByteString*           a_pCertificate,
    OpcUa_ByteString*           a_pIssuer,
    OpcUa_ByteString*           a_pSubject,
    OpcUa_ByteString*           a_pSubjectUri,
    OpcUa_ByteString*           a_pSubjectIP,
    OpcUa_ByteString*           a_pSubjectDNS,
    OpcUa_ByteString*           a_pCertThumbprint,
    OpcUa_UInt32*               a_pSubjectHash,
    OpcUa_UInt32*               a_pCertRawLength)
{
    X509*                       pX509Cert = OpcUa_Null;
    char*                       pName = OpcUa_Null;
    GENERAL_NAMES*              pNames = OpcUa_Null;
    const unsigned char*        p;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "PKI_ExtractCertificateData");

    OpcUa_ReturnErrorIfArgumentNull(a_pCertificate);

    if(a_pIssuer != OpcUa_Null)
    {
        a_pIssuer->Data = OpcUa_Null;
        a_pIssuer->Length = 0;
    }

    if(a_pSubject != OpcUa_Null)
    {
        a_pSubject->Data = OpcUa_Null;
        a_pSubject->Length = 0;
    }

    if(a_pSubjectUri != OpcUa_Null)
    {
        a_pSubjectUri->Data = OpcUa_Null;
        a_pSubjectUri->Length = 0;
    }

    if(a_pSubjectIP != OpcUa_Null)
    {
        a_pSubjectIP->Data = OpcUa_Null;
        a_pSubjectIP->Length = 0;
    }

    if(a_pSubjectDNS != OpcUa_Null)
    {
        a_pSubjectDNS->Data = OpcUa_Null;
        a_pSubjectDNS->Length = 0;
    }

    if(a_pCertThumbprint != OpcUa_Null)
    {
        a_pCertThumbprint->Data = OpcUa_Null;
        a_pCertThumbprint->Length = 0;
    }

    if(a_pSubjectHash != OpcUa_Null)
    {
        *a_pSubjectHash = 0;
    }

    if(a_pCertRawLength != OpcUa_Null)
    {
        *a_pCertRawLength = 0;
    }

    /* convert openssl X509 certificate to DER encoded bytestring certificate */
    p = a_pCertificate->Data;
    if(!(pX509Cert = d2i_X509((X509**)OpcUa_Null, &p, a_pCertificate->Length)))
    {
        uStatus = OpcUa_Bad;
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pIssuer != OpcUa_Null)
    {
        pName = X509_NAME_oneline(X509_get_issuer_name(pX509Cert), NULL, 0);
        OpcUa_GotoErrorIfAllocFailed(pName);
        a_pIssuer->Length = strlen(pName)+1;
        a_pIssuer->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pIssuer->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pIssuer->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pIssuer->Data, a_pIssuer->Length, pName, a_pIssuer->Length);
        OpcUa_GotoErrorIfBad(uStatus);
        OPENSSL_free(pName);
        pName = OpcUa_Null;
    }

    if(a_pSubject != OpcUa_Null)
    {
        pName = X509_NAME_oneline(X509_get_subject_name(pX509Cert), NULL, 0);
        OpcUa_GotoErrorIfAllocFailed(pName);
        a_pSubject->Length = strlen(pName)+1;
        a_pSubject->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubject->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pSubject->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pSubject->Data, a_pSubject->Length, pName, a_pSubject->Length);
        OpcUa_GotoErrorIfBad(uStatus);
        OPENSSL_free(pName);
        pName = OpcUa_Null;
    }

    if(a_pSubjectUri != OpcUa_Null || a_pSubjectIP != OpcUa_Null || a_pSubjectDNS != OpcUa_Null)
    {
        pNames = X509_get_ext_d2i(pX509Cert, NID_subject_alt_name, OpcUa_Null, OpcUa_Null);
        if (pNames != OpcUa_Null)
        {
            int num;
            for (num = 0; num < sk_GENERAL_NAME_num(pNames); num++)
            {
                GENERAL_NAME *value = sk_GENERAL_NAME_value(pNames, num);
                switch (value->type)
                {
                case GEN_URI:
                    if (a_pSubjectUri != OpcUa_Null && a_pSubjectUri->Data == OpcUa_Null)
                    {
                        a_pSubjectUri->Length = value->d.ia5->length+1;
                        a_pSubjectUri->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectUri->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectUri->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectUri->Data, a_pSubjectUri->Length, value->d.ia5->data, a_pSubjectUri->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;

                case GEN_IPADD:
                    if (a_pSubjectIP != OpcUa_Null && a_pSubjectIP->Data == OpcUa_Null)
                    {
                        a_pSubjectIP->Length = value->d.ip->length;
                        a_pSubjectIP->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectIP->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectIP->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectIP->Data, a_pSubjectIP->Length, value->d.ip->data, a_pSubjectIP->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;

                case GEN_DNS:
                    if (a_pSubjectDNS != OpcUa_Null && a_pSubjectDNS->Data == OpcUa_Null)
                    {
                        a_pSubjectDNS->Length = value->d.ia5->length+1;
                        a_pSubjectDNS->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pSubjectDNS->Length*sizeof(OpcUa_Byte));
                        OpcUa_GotoErrorIfAllocFailed(a_pSubjectDNS->Data);
                        uStatus = OpcUa_P_Memory_MemCpy(a_pSubjectDNS->Data, a_pSubjectDNS->Length, value->d.ia5->data, a_pSubjectDNS->Length);
                        OpcUa_GotoErrorIfBad(uStatus);
                    }
                break;
                }
            }
            sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
            pNames = OpcUa_Null;
        }
    }

    if(a_pCertThumbprint != OpcUa_Null)
    {
        /* update pX509Cert->sha1_hash */
        X509_check_purpose(pX509Cert, -1, 0);
        a_pCertThumbprint->Length = sizeof(pX509Cert->sha1_hash);
        a_pCertThumbprint->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pCertThumbprint->Length*sizeof(OpcUa_Byte));
        OpcUa_GotoErrorIfAllocFailed(a_pCertThumbprint->Data);
        uStatus = OpcUa_P_Memory_MemCpy(a_pCertThumbprint->Data, a_pCertThumbprint->Length, pX509Cert->sha1_hash, a_pCertThumbprint->Length);
        OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pSubjectHash != OpcUa_Null)
    {
        *a_pSubjectHash = X509_NAME_hash(X509_get_subject_name(pX509Cert));
    }

    if(a_pCertRawLength != OpcUa_Null)
    {
        *a_pCertRawLength = (OpcUa_UInt32)(p - a_pCertificate->Data);
    }

    X509_free(pX509Cert);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(a_pIssuer != OpcUa_Null && a_pIssuer->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pIssuer->Data);
        a_pIssuer->Data = OpcUa_Null;
        a_pIssuer->Length = 0;
    }

    if(a_pSubject != OpcUa_Null && a_pSubject->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubject->Data);
        a_pSubject->Data = OpcUa_Null;
        a_pSubject->Length = 0;
    }

    if(a_pSubjectUri != OpcUa_Null && a_pSubjectUri->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectUri->Data);
        a_pSubjectUri->Data = OpcUa_Null;
        a_pSubjectUri->Length = 0;
    }

    if(a_pSubjectIP != OpcUa_Null && a_pSubjectIP->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectIP->Data);
        a_pSubjectIP->Data = OpcUa_Null;
        a_pSubjectIP->Length = 0;
    }

    if(a_pSubjectDNS != OpcUa_Null && a_pSubjectDNS->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pSubjectDNS->Data);
        a_pSubjectDNS->Data = OpcUa_Null;
        a_pSubjectDNS->Length = 0;
    }

    if(a_pCertThumbprint != OpcUa_Null && a_pCertThumbprint->Data != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(a_pCertThumbprint->Data);
        a_pCertThumbprint->Data = OpcUa_Null;
        a_pCertThumbprint->Length = 0;
    }

    if (pName != OpcUa_Null)
    {
        OPENSSL_free(pName);
    }

    if (pNames != OpcUa_Null)
    {
        sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
    }

    if(pX509Cert != OpcUa_Null)
    {
        X509_free(pX509Cert);
    }

OpcUa_FinishErrorHandling;
}
OpcUa_StatusCode  fill_Variant_for_value_attribute(_VariableKnoten_*  p_Node, OpcUa_String* p_Index, OpcUa_DataValue* p_Results)
{
	OpcUa_Int					i;
	OpcUa_StatusCode			uStatus     = OpcUa_Good;
	extern my_Variant			all_ValueAttribute_of_VariableTypeNodes_VariableNodes[];

	OpcUa_ReturnErrorIfArgumentNull(p_Node);
	/*OpcUa_ReturnErrorIfArgumentNull(p_Index);*/
	OpcUa_ReturnErrorIfArgumentNull(p_Results);
	if(p_Node->ValueIndex == (-1))
	{
		OpcUa_GotoErrorWithStatus(OpcUa_BadNotReadable)
	}
	
	if(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].ArrayType==OpcUa_VariantArrayType_Scalar)
	{
		switch(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Datatype)
		{
		case OpcUaId_Double:
			{
				p_Results->Value.Value.Double=all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Double;
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_Double, OpcUa_VariantArrayType_Scalar,0);
				break;
			}
		case OpcUaId_DateTime:
			{
				p_Results->Value.Value.DateTime=all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.DateTime;
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_DateTime, OpcUa_VariantArrayType_Scalar,0);
				break;
			}
		case OpcUaId_String:
			{
				uStatus= OpcUa_String_AttachCopy(&(p_Results->Value.Value.String),all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.String);
				OpcUa_GotoErrorIfBad(uStatus)
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_String, OpcUa_VariantArrayType_Scalar,0);
				break;
			}
		case OpcUaId_UInt32:
			{
				p_Results->Value.Value.UInt32=all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.UInt32;
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_UInt32, OpcUa_VariantArrayType_Scalar,0);
				break;
			}
		case OpcUaId_Boolean:
			{
				p_Results->Value.Value.Boolean=all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Boolean;
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
				break;
			}
		}
	
	}

	if(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].ArrayType==OpcUa_VariantArrayType_Array)
	{
		switch(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Datatype)
		{
		case OpcUaId_Double:
			{
				p_Results->Value.Value.Array.Value.DoubleArray=OpcUa_Memory_Alloc((all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Double));
				OpcUa_GotoErrorIfAllocFailed((p_Results->Value.Value.Array.Value.DoubleArray))
				
				OpcUa_MemCpy((p_Results->Value.Value.Array.Value.DoubleArray),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Double),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Value.DoubleArray),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Double));
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_Double, OpcUa_VariantArrayType_Array,all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length);
				break;
			}
		case OpcUaId_String:
			{
				p_Results->Value.Value.Array.Value.StringArray=OpcUa_Memory_Alloc((all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_String));
				OpcUa_GotoErrorIfAllocFailed((p_Results->Value.Value.Array.Value.DoubleArray))

				for(i=0;i<(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length);i++)
				{
					uStatus= OpcUa_String_AttachCopy((p_Results->Value.Value.Array.Value.StringArray)+i,*(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Value.StringArray+i));
					if(OpcUa_IsBad(uStatus))
						OpcUa_GotoError
				}
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_String, OpcUa_VariantArrayType_Array,all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length);
				break;
			}
		case OpcUaId_UInt32:
			{
				p_Results->Value.Value.Array.Value.UInt32Array=OpcUa_Memory_Alloc((all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_UInt32));
				OpcUa_GotoErrorIfAllocFailed((p_Results->Value.Value.Array.Value.UInt32Array))

				OpcUa_MemCpy((p_Results->Value.Value.Array.Value.UInt32Array),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_UInt32),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Value.UInt32Array),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_UInt32));
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_UInt32, OpcUa_VariantArrayType_Array,all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length);
				break;
			}
		case OpcUaId_Boolean:
			{
				p_Results->Value.Value.Array.Value.BooleanArray=OpcUa_Memory_Alloc((all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Boolean));
				OpcUa_GotoErrorIfAllocFailed((p_Results->Value.Value.Array.Value.BooleanArray))

				OpcUa_MemCpy((p_Results->Value.Value.Array.Value.BooleanArray),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Boolean),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Value.BooleanArray),(all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length)*sizeof(OpcUa_Boolean));
				fill_datatype_arraytype_in_my_Variant(p_Results,OpcUaId_UInt32, OpcUa_VariantArrayType_Array,all_ValueAttribute_of_VariableTypeNodes_VariableNodes[p_Node->ValueIndex].Value.Array.Length);
				break;
			}
		}
	}
	
	OpcUa_ReturnStatusCode;
    OpcUa_BeginErrorHandling;
	
	p_Results->StatusCode=uStatus;
	OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_ParseUrl
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_ParseUrl(  OpcUa_StringA   a_psUrl,
                                    OpcUa_StringA*  a_psIpAdress,
                                    OpcUa_UInt16*   a_puPort)
{
    OpcUa_UInt32    uUrlLength        = 0;

    OpcUa_StringA   sHostName         = OpcUa_Null;
    OpcUa_UInt32    uHostNameLength   = 0;

    OpcUa_CharA*    pcCursor          = OpcUa_Null;

    OpcUa_Int       nIndex1           = 0;
    OpcUa_Int       nIpStart          = 0;

    struct hostent* pHostEnt          = OpcUa_Null;

OpcUa_InitializeStatus(OpcUa_Module_Utilities, "P_ParseUrl");

    OpcUa_ReturnErrorIfArgumentNull(a_psUrl);
    OpcUa_ReturnErrorIfArgumentNull(a_psIpAdress);
    OpcUa_ReturnErrorIfArgumentNull(a_puPort);

    *a_psIpAdress = OpcUa_Null;

    uUrlLength = (OpcUa_UInt32)strlen(a_psUrl);

    /* check for // (end of protocol header) */
    pcCursor = strstr(a_psUrl, "//");

    if(pcCursor != OpcUa_Null)
    {
        /* begin of host address */
        pcCursor += 2;
        nIndex1 = (OpcUa_Int)(pcCursor - a_psUrl);
    }
    else
    {
        uStatus = OpcUa_BadSyntaxError;
        OpcUa_ReturnStatusCode;
    }

    /* skip protocol prefix and store beginning of ip adress */
    nIpStart = nIndex1;

    /* skip host address */
    while(      a_psUrl[nIndex1] != ':'
            &&  a_psUrl[nIndex1] != '/'
            &&  a_psUrl[nIndex1] != 0
            &&  nIndex1          <  (OpcUa_Int32)uUrlLength)
    {
        nIndex1++;
    }

    uHostNameLength = nIndex1 - nIpStart;
    sHostName       = (OpcUa_StringA)malloc(uHostNameLength + 1);
    if(sHostName == NULL)
    {
        return OpcUa_BadOutOfMemory;
    }

    memcpy(sHostName, &a_psUrl[nIpStart], uHostNameLength);
    sHostName[uHostNameLength] = '\0';

    pHostEnt = gethostbyname(sHostName);

    free(sHostName);

    if(pHostEnt == NULL)
    {
        /* hostname could not be resolved */
        return OpcUa_BadHostUnknown;
    }

    nIpStart = 0;
    *a_psIpAdress = (OpcUa_StringA)OpcUa_P_Memory_Alloc(16);
    memset(*a_psIpAdress, 0, 16);

#if OPCUA_USE_SAFE_FUNCTIONS
    nIpStart += sprintf_s(&(*a_psIpAdress)[0],         16,"%u", (unsigned char)(*((*pHostEnt).h_addr_list))[0]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf_s(&(*a_psIpAdress)[nIpStart],  12,"%u", (unsigned char)(*((*pHostEnt).h_addr_list))[1]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf_s(&(*a_psIpAdress)[nIpStart],   8,"%u", (unsigned char)(*((*pHostEnt).h_addr_list))[2]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf_s(&(*a_psIpAdress)[nIpStart],   4,"%u", (unsigned char)(*((*pHostEnt).h_addr_list))[3]);
#else /* OPCUA_USE_SAFE_FUNCTIONS */

    nIpStart += sprintf(&(*a_psIpAdress)[0], "%u", (unsigned char)(*((*pHostEnt).h_addr_list))[0]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf(&(*a_psIpAdress)[nIpStart], "%u", (unsigned char)(*((*pHostEnt).h_addr_list))[1]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf(&(*a_psIpAdress)[nIpStart], "%u", (unsigned char)(*((*pHostEnt).h_addr_list))[2]);
    (*a_psIpAdress)[nIpStart++] = '.';
    nIpStart += sprintf(&(*a_psIpAdress)[nIpStart], "%u", (unsigned char)(*((*pHostEnt).h_addr_list))[3]);
#endif /* OPCUA_USE_SAFE_FUNCTIONS */

    /* scan port */
    if(a_psUrl[nIndex1] == ':')
    {
        OpcUa_Int       nIndex2 = 0;
        OpcUa_CharA*    sPort   = OpcUa_Null;
        OpcUa_CharA sBuffer[MAX_PORT_LENGTH];

        /* skip delimiter */
        nIndex1++;

        /* store beginning of port */
        sPort = &a_psUrl[nIndex1];

        /* search for end of port */
        while(      a_psUrl[nIndex1] != '/'
                &&  a_psUrl[nIndex1] != 0
                &&  nIndex2          <  6)
        {
            nIndex1++;
            nIndex2++;
        }

        /* convert port */
        OpcUa_P_Memory_MemCpy(sBuffer, MAX_PORT_LENGTH-1, sPort, nIndex2);
        sBuffer[nIndex2] = 0;
        *a_puPort = (OpcUa_UInt16)OpcUa_P_CharAToInt(sBuffer);
    }
    else
    {
        /* return default port */
        if (strncmp(a_psUrl, "http:", 5) != 0)
        {
            *a_puPort = OPCUA_TCP_DEFAULT_PORT;
        }
        else
        {
            *a_puPort = OPCUA_HTTP_DEFAULT_PORT;
        }
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/*============================================================================
 * method which implements the Read service.
 *===========================================================================*/
OpcUa_StatusCode my_Read(
							OpcUa_Endpoint             a_hEndpoint,
							OpcUa_Handle               a_hContext,
							const OpcUa_RequestHeader* a_pRequestHeader,
							OpcUa_Double               a_nMaxAge,
							OpcUa_TimestampsToReturn   a_eTimestampsToReturn,
							OpcUa_Int32                a_nNoOfNodesToRead,
							const OpcUa_ReadValueId*   a_pNodesToRead,
							OpcUa_ResponseHeader*      a_pResponseHeader,
							OpcUa_Int32*               a_pNoOfResults,
							OpcUa_DataValue**          a_pResults,
							OpcUa_Int32*               a_pNoOfDiagnosticInfos,
							OpcUa_DiagnosticInfo**     a_pDiagnosticInfos)
{
	OpcUa_Int i,n;
	OpcUa_Void* p_Node;
	extern OpcUa_UInt32		securechannelId;
	extern OpcUa_UInt32		session_flag;
	extern OpcUa_Double		msec_counter;
	extern OpcUa_String*	p_user_name;

    OpcUa_InitializeStatus(OpcUa_Module_Server, "OpcUa_ServerApi_Read");

    /* validate arguments. */
    OpcUa_ReturnErrorIfArgumentNull(a_hEndpoint);
    OpcUa_ReturnErrorIfArgumentNull(a_hContext);
    OpcUa_ReturnErrorIfArgumentNull(a_pRequestHeader);
    OpcUa_ReferenceParameter(a_nMaxAge);
    OpcUa_ReferenceParameter(a_eTimestampsToReturn);
    OpcUa_ReturnErrorIfArrayArgumentNull(a_nNoOfNodesToRead, a_pNodesToRead);
    OpcUa_ReturnErrorIfArgumentNull(a_pResponseHeader);
    OpcUa_ReturnErrorIfArrayArgumentNull(a_pNoOfResults, a_pResults);
    OpcUa_ReturnErrorIfArrayArgumentNull(a_pNoOfDiagnosticInfos, a_pDiagnosticInfos);

	*a_pNoOfDiagnosticInfos=0;
	*a_pDiagnosticInfos=OpcUa_Null;

	RESET_SESSION_COUNTER

 #ifndef NO_DEBUGING_
	MY_TRACE("\n\n\nRREADSERVICE==============================================\n");
	if(p_user_name!=OpcUa_Null)
		MY_TRACE("\nUser:%s\n",OpcUa_String_GetRawString(p_user_name)); 
#endif /*_DEBUGING_*/
  

	if(OpcUa_IsBad(session_flag))
	{
		//teile client mit , dass Session geschlossen ist
#ifndef NO_DEBUGING_
		MY_TRACE("\nSession nicht aktiv\n"); 
#endif /*_DEBUGING_*/
		uStatus=OpcUa_BadSessionNotActivated;
		OpcUa_GotoError;
	}

	
	uStatus=check_authentication_token(a_pRequestHeader);
	if(OpcUa_IsBad(uStatus))
	{
#ifndef NO_DEBUGING_
		MY_TRACE("\nAuthentication Token ungültig.\n"); 
#endif /*_DEBUGING_*/
		OpcUa_GotoError;
	}

	*a_pResults=OpcUa_Alloc(a_nNoOfNodesToRead*sizeof(OpcUa_DataValue));
	OpcUa_GotoErrorIfAllocFailed((*a_pResults))
	

	for(n=0;n<a_nNoOfNodesToRead;n++)
	{
		OpcUa_DataValue_Initialize((*a_pResults)+n);
		((*a_pResults)+n)->StatusCode=OpcUa_BadAttributeIdInvalid;
		p_Node=search_for_node((a_pNodesToRead+n)->NodeId);
		if(p_Node!= OpcUa_Null)   //pruefe ob Knoten existiert
		{
			if(((a_pNodesToRead+n)->AttributeId)<=7 && ((a_pNodesToRead+n)->AttributeId)>=1)
			{
				if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_NodeId)
				{
					((*a_pResults)+n)->Value.Value.NodeId=OpcUa_Memory_Alloc(sizeof(OpcUa_NodeId));
					if(((*a_pResults)+n)->Value.Value.NodeId !=OpcUa_Null)
					{
						OpcUa_NodeId_Initialize(((*a_pResults)+n)->Value.Value.NodeId);
						*(((*a_pResults)+n)->Value.Value.NodeId)=((_ObjectKnoten_*)p_Node)->BaseAttribute.NodeId; 
						fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_NodeId, OpcUa_VariantArrayType_Scalar,0);
						((*a_pResults)+n)->StatusCode=OpcUa_Good;
					}
					else
					{
						((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
					}
				}
				if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_NodeClass)
				{
					((*a_pResults)+n)->Value.Value.Int32=((_ObjectKnoten_*)p_Node)->BaseAttribute.NodeClass;
					fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Int32, OpcUa_VariantArrayType_Scalar,0);
					((*a_pResults)+n)->StatusCode=OpcUa_Good;
				}
				if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_BrowseName)
				{
					((*a_pResults)+n)->Value.Value.QualifiedName=OpcUa_Memory_Alloc(sizeof(OpcUa_QualifiedName));
					if(((*a_pResults)+n)->Value.Value.QualifiedName!=OpcUa_Null)
					{
						OpcUa_QualifiedName_Initialize(((*a_pResults)+n)->Value.Value.QualifiedName);
						OpcUa_String_AttachCopy(&((*a_pResults)+n)->Value.Value.QualifiedName->Name,((_ObjectKnoten_*)p_Node)->BaseAttribute.BrowseName);
						((*a_pResults)+n)->Value.Value.QualifiedName->NamespaceIndex=((_ObjectKnoten_*)p_Node)->BaseAttribute.NodeId.NamespaceIndex;     
						fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_QualifiedName, OpcUa_VariantArrayType_Scalar,0);
						((*a_pResults)+n)->StatusCode=OpcUa_Good;
					}
					else
					{
						((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
					}
				}
				if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_DisplayName)
				{
					((*a_pResults)+n)->Value.Value.LocalizedText=OpcUa_Memory_Alloc(sizeof(OpcUa_LocalizedText));
					if(((*a_pResults)+n)->Value.Value.LocalizedText!=OpcUa_Null)
					{
						OpcUa_LocalizedText_Initialize(((*a_pResults)+n)->Value.Value.LocalizedText);
						OpcUa_String_AttachCopy(&((*a_pResults)+n)->Value.Value.LocalizedText->Text,((_ObjectKnoten_*)p_Node)->BaseAttribute.DisplayName);
						OpcUa_String_AttachCopy(&((*a_pResults)+n)->Value.Value.LocalizedText->Locale,"en");
						fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_LocalizedText, OpcUa_VariantArrayType_Scalar,0);
						((*a_pResults)+n)->StatusCode=OpcUa_Good;
					}
					else
					{
						((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
					}

				}
				if(((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_Description || (a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_WriteMask) || (a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_UserWriteMask)
				{
						((*a_pResults)+n)->StatusCode=OpcUa_BadNotReadable;
				}
			}
			else
			{
				switch((((_ObjectKnoten_*)p_Node)->BaseAttribute.NodeClass))
				{
				case OpcUa_NodeClass_Variable:
					{
						if((a_pNodesToRead+n)->AttributeId<=20 && (a_pNodesToRead+n)->AttributeId>=13)
						{
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_Value)
							{
								 ((*a_pResults)+n)->StatusCode=fill_Variant_for_value_attribute((_VariableKnoten_*)p_Node, OpcUa_Null,((*a_pResults)+n));
								if(a_eTimestampsToReturn!=OpcUa_TimestampsToReturn_Neither)
								{
									uStatus=assigne_Timestamp(((*a_pResults)+n),a_eTimestampsToReturn);
									if(OpcUa_IsBad(uStatus))
									{
										((*a_pResults)+n)->StatusCode=OpcUa_BadInternalError;
										uStatus=OpcUa_Good;
									}
								}
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_DataType)
							{
								((*a_pResults)+n)->Value.Value.NodeId=OpcUa_Memory_Alloc(sizeof(OpcUa_NodeId));
								if(((*a_pResults)+n)->Value.Value.NodeId!=OpcUa_Null)
								{
									OpcUa_NodeId_Initialize(((*a_pResults)+n)->Value.Value.NodeId);
									*(((*a_pResults+n)->Value.Value.NodeId))=((_VariableKnoten_*)p_Node)->DataType;
									fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_NodeId, OpcUa_VariantArrayType_Scalar,0);
									((*a_pResults)+n)->StatusCode=OpcUa_Good;
								}
								else
								{
									((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
								}
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_ValueRank)
							{
								((*a_pResults)+n)->Value.Value.Int32=((_VariableKnoten_*)p_Node)->ValueRank;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Int32, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_ArrayDimensions)
							{
								
								((*a_pResults)+n)->Value.Value.UInt32=(((_VariableKnoten_*)p_Node)->ArrayDimensions);
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_UInt32, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;

							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_AccessLevel)
							{
								((*a_pResults)+n)->Value.Value.Byte=((_VariableKnoten_*)p_Node)->AccessLevel;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Byte, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_UserAccessLevel)
							{
								((*a_pResults)+n)->Value.Value.Byte=((_VariableKnoten_*)p_Node)->UserAccessLevel;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Byte, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_MinimumSamplingInterval)
							{
								((*a_pResults)+n)->Value.Value.Double=OpcUa_MinimumSamplingIntervals_Indeterminate;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Double, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_Historizing)
							{
								((*a_pResults)+n)->Value.Value.Boolean=((_VariableKnoten_*)p_Node)->Historizing;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
						}
						break;
					}
				case OpcUa_NodeClass_VariableType:
					{
						if(((a_pNodesToRead+n)->AttributeId<=16 && (a_pNodesToRead+n)->AttributeId>=13) ||((a_pNodesToRead+n)->AttributeId==8))
						{
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_Value)
							{
								 ((*a_pResults)+n)->StatusCode=fill_Variant_for_value_attribute((_VariableKnoten_*)p_Node, OpcUa_Null,((*a_pResults)+n));
								if(a_eTimestampsToReturn!=OpcUa_TimestampsToReturn_Neither)
								{
									uStatus=assigne_Timestamp(((*a_pResults)+n),a_eTimestampsToReturn);
									if(OpcUa_IsBad(uStatus))
									{
										((*a_pResults)+n)->StatusCode=OpcUa_BadInternalError;
										uStatus=OpcUa_Good;
									}
								}
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_DataType)
							{
								((*a_pResults)+n)->Value.Value.NodeId=OpcUa_Memory_Alloc(sizeof(OpcUa_NodeId));
								if(((*a_pResults)+n)->Value.Value.NodeId!=OpcUa_Null)
								{
									OpcUa_NodeId_Initialize(((*a_pResults)+n)->Value.Value.NodeId);
									*((*a_pResults)+n)->Value.Value.NodeId=((_VariableTypeKnoten_*)p_Node)->DataType;
									fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_NodeId, OpcUa_VariantArrayType_Scalar,0);
									((*a_pResults)+n)->StatusCode=OpcUa_Good;
								}
								else
								{
									((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
								}
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_ArrayDimensions)
							{
								((*a_pResults)+n)->Value.Value.UInt32=((_VariableTypeKnoten_*)p_Node)->ArrayDimensions; 
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_UInt32, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_IsAbstract)
							{
								((*a_pResults)+n)->Value.Value.Boolean=((_VariableTypeKnoten_*)p_Node)->IsAbstract;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							
						}
						break;
					}
				case OpcUa_NodeClass_Object:
					{
						if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_EventNotifier)
						{
							((*a_pResults)+n)->Value.Value.Byte=((_ObjectKnoten_*)p_Node)->EventNotifier;
							fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Byte, OpcUa_VariantArrayType_Scalar,0);
							((*a_pResults)+n)->StatusCode=OpcUa_Good;
						}
						break;
					}
					
				case OpcUa_NodeClass_ObjectType:
					{
						if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_IsAbstract)
						{
							((*a_pResults)+n)->Value.Value.Boolean=((_ObjectTypeKnoten_*)p_Node)->IsAbstract;
							fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
							((*a_pResults)+n)->StatusCode=OpcUa_Good;
						}
						break;
					}
					
				case OpcUa_NodeClass_DataType:
					{

						if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_IsAbstract)
						{
							((*a_pResults)+n)->Value.Value.Boolean=((_DataTypeKnoten_*)p_Node)->IsAbstract;
							fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
							((*a_pResults)+n)->StatusCode=OpcUa_Good;
						}
						break;
					}
				
				case OpcUa_NodeClass_ReferenceType:
					{
						if((a_pNodesToRead+n)->AttributeId<=10 && (a_pNodesToRead+n)->AttributeId>=8)
						{
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_IsAbstract)
							{
								((*a_pResults)+n)->Value.Value.Boolean=((_ReferenceTypeKnoten_*)p_Node)->IsAbstract;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_Symmetric)
							{
								((*a_pResults)+n)->Value.Value.Boolean=((_ReferenceTypeKnoten_*)p_Node)->Symmetric;
								fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_Boolean, OpcUa_VariantArrayType_Scalar,0);
								((*a_pResults)+n)->StatusCode=OpcUa_Good;
							}
							if((a_pNodesToRead+n)->AttributeId==OpcUa_Attributes_InverseName)
							{
								((*a_pResults)+n)->Value.Value.LocalizedText=OpcUa_Memory_Alloc(sizeof(OpcUa_LocalizedText));
								if(((*a_pResults)+n)->Value.Value.NodeId!=OpcUa_Null)
								{
									OpcUa_LocalizedText_Initialize(((*a_pResults)+n)->Value.Value.LocalizedText);
									OpcUa_String_AttachCopy(&((*a_pResults)+n)->Value.Value.LocalizedText->Text, ((_ReferenceTypeKnoten_*)p_Node)->InverseName_text);
									OpcUa_String_AttachCopy(&((*a_pResults)+n)->Value.Value.LocalizedText->Locale, ((_ReferenceTypeKnoten_*)p_Node)->InverseName_locale);
									fill_datatype_arraytype_in_my_Variant(((*a_pResults)+n),OpcUaId_LocalizedText, OpcUa_VariantArrayType_Scalar,0);
									((*a_pResults)+n)->StatusCode=OpcUa_Good;
								}
								else
								{
									((*a_pResults)+n)->StatusCode=OpcUa_BadOutOfMemory;
								}
							}
						}
						break;
					}
				default:
					break;
					
				
				}
			}
			
		
		}
		else
		{
			((*a_pResults)+n)->StatusCode=OpcUa_BadNodeIdUnknown;
		}
		
	}
	
	

	*a_pNoOfResults=a_nNoOfNodesToRead;

#ifndef NO_DEBUGING_
	MY_TRACE("\nanzahl der nodes :%d\n",a_nNoOfNodesToRead);
	for(i=0;i<a_nNoOfNodesToRead;i++)
	{
		MY_TRACE("\n|%d|, |%d| attributeId:%u\n",(a_pNodesToRead+i)->NodeId.NamespaceIndex,(a_pNodesToRead+i)->NodeId.Identifier.Numeric,(a_pNodesToRead+i)->AttributeId);
		
	}
#endif /*_DEBUGING_*/


	
	uStatus = response_header_ausfuellen(a_pResponseHeader,a_pRequestHeader,uStatus);
	if(OpcUa_IsBad(uStatus))
	{
       a_pResponseHeader->ServiceResult=OpcUa_BadInternalError;
	}
#ifndef NO_DEBUGING_
	MY_TRACE("\nSERVICE===ENDE============================================\n\n\n"); 
#endif /*_DEBUGING_*/

	RESET_SESSION_COUNTER

    OpcUa_ReturnStatusCode;
    OpcUa_BeginErrorHandling;

    
	uStatus = response_header_ausfuellen(a_pResponseHeader,a_pRequestHeader,uStatus);
	if(OpcUa_IsBad(uStatus))
	{
       a_pResponseHeader->ServiceResult=OpcUa_BadInternalError;
	}
#ifndef NO_DEBUGING_
	MY_TRACE("\nSERVICEENDE (IM SERVICE SIND FEHLER AUFGETRETTEN)===========\n\n\n"); 
#endif /*_DEBUGING_*/
	RESET_SESSION_COUNTER
    OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_RSA_LoadPrivateKeyFromFile(
    OpcUa_StringA           a_privateKeyFile,
    OpcUa_P_FileFormat      a_fileFormat,
    OpcUa_StringA           a_password,         /* optional: just needed encrypted PEM */
    OpcUa_ByteString*       a_pPrivateKey)
{
    BIO*            pPrivateKeyFile     = OpcUa_Null;
    RSA*            pRsaPrivateKey      = OpcUa_Null;
    EVP_PKEY*       pEvpKey             = OpcUa_Null;
    unsigned char*  pData;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "RSA_LoadPrivateKeyFromFile");

    /* check parameters */
    OpcUa_ReturnErrorIfArgumentNull(a_privateKeyFile);
    OpcUa_ReturnErrorIfArgumentNull(a_pPrivateKey);

    if(a_fileFormat == OpcUa_Crypto_Encoding_Invalid)
    {
        return OpcUa_BadInvalidArgument;
    }

    OpcUa_ReferenceParameter(a_password);

    /* open file */
    pPrivateKeyFile = BIO_new_file((const char*)a_privateKeyFile, "rb");
    OpcUa_ReturnErrorIfArgumentNull(pPrivateKeyFile);

    /* read and convert file */
    switch(a_fileFormat)
    {
    case OpcUa_Crypto_Encoding_PEM:
        {
            /* read from file */
            pEvpKey = PEM_read_bio_PrivateKey(  pPrivateKeyFile,    /* file                 */
                                                NULL,               /* key struct           */
                                                0,                  /* password callback    */
                                                a_password);        /* default passphrase or arbitrary handle */
            OpcUa_GotoErrorIfNull(pEvpKey, OpcUa_Bad);
            break;
        }
    case OpcUa_Crypto_Encoding_PKCS12:
        {
            int iResult = 0;

            /* read from file. */
            PKCS12* pPkcs12 = d2i_PKCS12_bio(pPrivateKeyFile, NULL);

            if (pPkcs12 == 0)
            {
                OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError);
            }

            /*  parse the certificate. */
            iResult = PKCS12_parse(pPkcs12, a_password, &pEvpKey, NULL, NULL);

            if (iResult == 0)
            {
                OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError);
            }

            /*  free certificate. */
            PKCS12_free(pPkcs12);
            pPkcs12 = NULL;
            break;
        }
    case OpcUa_Crypto_Encoding_DER:
    default:
        {
            uStatus = OpcUa_BadNotSupported;
            OpcUa_GotoError;
        }
    }

    /* convert to intermediary openssl struct */
    pRsaPrivateKey = EVP_PKEY_get1_RSA(pEvpKey);
    EVP_PKEY_free(pEvpKey);
    OpcUa_GotoErrorIfNull(pRsaPrivateKey, OpcUa_Bad);

    /* get required length */
    a_pPrivateKey->Length = i2d_RSAPrivateKey(pRsaPrivateKey, OpcUa_Null);
    OpcUa_GotoErrorIfTrue((a_pPrivateKey->Length <= 0), OpcUa_Bad);

    /* allocate target buffer */
    a_pPrivateKey->Data = (OpcUa_Byte*)OpcUa_P_Memory_Alloc(a_pPrivateKey->Length);
    OpcUa_GotoErrorIfAllocFailed(a_pPrivateKey->Data);

    /* do real conversion */
    pData = a_pPrivateKey->Data;
    a_pPrivateKey->Length = i2d_RSAPrivateKey(pRsaPrivateKey, &pData);
    OpcUa_GotoErrorIfTrue((a_pPrivateKey->Length <= 0), OpcUa_Bad);

    RSA_free(pRsaPrivateKey);
    BIO_free(pPrivateKeyFile);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pEvpKey)
    {
        EVP_PKEY_free(pEvpKey);
    }

    if(a_pPrivateKey != OpcUa_Null)
    {
        if(a_pPrivateKey->Data != OpcUa_Null)
        {
            OpcUa_P_Memory_Free(a_pPrivateKey->Data);
            a_pPrivateKey->Data = OpcUa_Null;
            a_pPrivateKey->Length = -1;
        }
    }

    if(pPrivateKeyFile != NULL)
    {
        BIO_free(pPrivateKeyFile);
    }

    if(pRsaPrivateKey != NULL)
    {
        RSA_free(pRsaPrivateKey);
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_Random_Key_PSHA256_Derive
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_Random_Key_PSHA256_Derive(
    OpcUa_CryptoProvider* a_pProvider,
    OpcUa_ByteString      a_secret, /* clientnonce | servernonce, servernonce | clientnonce */
    OpcUa_ByteString      a_seed,
    OpcUa_Int32           a_keyLen, /* output len */
    OpcUa_Key*            a_pKey)
{
    OpcUa_P_OpenSSL_PSHA256_Ctx*pCtx            = OpcUa_Null;
    OpcUa_Byte*                 pBuffer         = OpcUa_Null;

    OpcUa_Int                   bufferlength;
    OpcUa_Int                   i;
    OpcUa_Int                   iterations;

    OpcUa_CryptoProviderConfig* pConfig         = OpcUa_Null;
    OpcUa_Int32                 keyLen          = 0;

OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "Random_Key_PSHA256_Derive");

    OpcUa_ReferenceParameter(a_pProvider);

    OpcUa_ReturnErrorIfArgumentNull(a_pProvider);
    OpcUa_ReturnErrorIfArgumentNull(a_secret.Data);
    OpcUa_ReturnErrorIfArgumentNull(a_seed.Data);
    OpcUa_ReturnErrorIfArgumentNull(a_pKey);

    keyLen = a_keyLen;

    if(keyLen < 0)
    {
        if(a_pProvider->Handle != OpcUa_Null)
        {
            /* get default configuration */
            pConfig = (OpcUa_CryptoProviderConfig*)a_pProvider->Handle;
            keyLen = pConfig->SymmetricKeyLength;
        }
        else
        {
            uStatus = OpcUa_BadInvalidArgument;
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }
    else if(keyLen > MAX_DERIVED_OUTPUT_LEN)
    {
            uStatus = OpcUa_BadInvalidArgument;
            OpcUa_GotoErrorIfBad(uStatus);
    }

    if(a_pKey->Key.Data == OpcUa_Null)
    {
        a_pKey->Key.Length = keyLen;
        OpcUa_ReturnStatusCode;
    }

    a_pKey->Type = OpcUa_Crypto_KeyType_Random;

    /** start creating key **/

    pCtx = (OpcUa_P_OpenSSL_PSHA256_Ctx*)OpcUa_Null;

    iterations = keyLen/32 + (keyLen%32?1:0);
    bufferlength = iterations*32;

    pBuffer = (OpcUa_Byte *)OpcUa_P_Memory_Alloc(bufferlength * sizeof(OpcUa_Byte));

    pCtx = OpcUa_P_OpenSSL_PSHA256_Context_Create(a_secret.Data, a_secret.Length, a_seed.Data, a_seed.Length);

    for(i=0; i<iterations; i++)
    {
        /* SHA256 produces 32 Bytes of output for every iteration */
        uStatus = OpcUa_P_OpenSSL_PSHA256_Hash_Generate(pCtx, pBuffer + (i*32));
        OpcUa_GotoErrorIfBad(uStatus);
    }

    OpcUa_P_Memory_MemCpy(a_pKey->Key.Data, a_pKey->Key.Length, pBuffer, keyLen);

    if(pCtx != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(pCtx);
        pCtx = OpcUa_Null;
    }

    if(pBuffer != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(pBuffer);
        pBuffer = OpcUa_Null;
    }

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pCtx != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(pCtx);
        pCtx = OpcUa_Null;
    }

    if(pBuffer != OpcUa_Null)
    {
        OpcUa_P_Memory_Free(pBuffer);
        pBuffer = OpcUa_Null;
    }

OpcUa_FinishErrorHandling;
}
/*============================================================================
 * OpcUa_P_OpenSSL_RSA_Private_Decrypt
 *===========================================================================*/
OpcUa_StatusCode OpcUa_P_OpenSSL_RSA_Private_Decrypt(
    OpcUa_CryptoProvider*   a_pProvider,
    OpcUa_Byte*             a_pCipherText,
    OpcUa_UInt32            a_cipherTextLen,
    OpcUa_Key*              a_privateKey,
    OpcUa_Int16             a_padding,
    OpcUa_Byte*             a_pPlainText,
    OpcUa_UInt32*           a_pPlainTextLen)
{
    EVP_PKEY*       pPrivateKey     = OpcUa_Null;

    OpcUa_UInt32    keySize         = 0;
    OpcUa_Int32     decryptedBytes  = 0;
    OpcUa_UInt32    iCipherText     = 0;
    /* OpcUa_UInt32 iPlainTextLen   = 0; */
    OpcUa_UInt32    decDataSize     = 0;

    const char*     sError          = OpcUa_Null;
    const unsigned char *pData;

    OpcUa_InitializeStatus(OpcUa_Module_P_OpenSSL, "RSA_Private_Decrypt");

    OpcUa_ReferenceParameter(a_pProvider);

    OpcUa_ReturnErrorIfArgumentNull(a_pCipherText);
    OpcUa_ReturnErrorIfArgumentNull(a_privateKey);
    OpcUa_ReturnErrorIfArgumentNull(a_privateKey->Key.Data);
    OpcUa_ReturnErrorIfArgumentNull(a_pPlainTextLen);

    *a_pPlainTextLen = 0;

    if(a_privateKey->Type != OpcUa_Crypto_KeyType_Rsa_Private)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadInvalidArgument);
    }

    pData = a_privateKey->Key.Data;
    pPrivateKey = d2i_PrivateKey(EVP_PKEY_RSA,OpcUa_Null, &pData, a_privateKey->Key.Length);

    if (pPrivateKey == OpcUa_Null)
    {
        long lErr = ERR_get_error();
        char *szErr = ERR_error_string(lErr, 0);
        OpcUa_ReferenceParameter(szErr);
        return OpcUa_BadInvalidArgument;
    }

    keySize = RSA_size(pPrivateKey->pkey.rsa);

    if((a_cipherTextLen%keySize) != 0)
    {
        uStatus = OpcUa_BadInvalidArgument;
        OpcUa_GotoError;
    }

    /* check padding type */
    switch(a_padding)
    {
    case RSA_PKCS1_PADDING:
        {
            decDataSize = keySize - 11;
            break;
        }
    case RSA_PKCS1_OAEP_PADDING:
        {
            decDataSize = keySize - 42;
            break;
        }
    case RSA_NO_PADDING:
        {
            decDataSize = keySize;
            break;
        }
    default:
        {
            OpcUa_GotoErrorWithStatus(OpcUa_BadNotSupported);
        }
    }

    while(iCipherText < a_cipherTextLen)
    {
        if(a_pPlainText != OpcUa_Null)
        {
            decryptedBytes = RSA_private_decrypt(   keySize,                            /* how much to decrypt  */
                                                    a_pCipherText + iCipherText,        /* what to decrypt      */
                                                    a_pPlainText + (*a_pPlainTextLen),  /* where to decrypt     */
                                                    pPrivateKey->pkey.rsa,              /* private key          */
                                                    a_padding);                         /* padding mode         */

            /* goto error block, if decryption fails */
            if(decryptedBytes == -1)
            {
                /* const char* serror = NULL; */
                unsigned long error = ERR_get_error();

                ERR_load_crypto_strings();

                sError = ERR_reason_error_string(error);
                sError = ERR_func_error_string(error);
                sError = ERR_lib_error_string(error);

                uStatus = OpcUa_Bad;
                OpcUa_GotoError;
            }

        }
        else
        {
            decryptedBytes = decDataSize;
        }

        *a_pPlainTextLen = *a_pPlainTextLen + decryptedBytes;
        iCipherText = iCipherText + keySize;
    }


    EVP_PKEY_free(pPrivateKey);

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    if(pPrivateKey != OpcUa_Null)
    {
        EVP_PKEY_free(pPrivateKey);
    }

    *a_pPlainTextLen = (OpcUa_UInt32)-1;

OpcUa_FinishErrorHandling;
}
static
OpcUa_StatusCode OpcUa_UadpNetworkMessageHeader_WriteBinary(OpcUa_UadpNetworkMessageHeader* a_pValue, OpcUa_Byte **a_pBuffer, OpcUa_UInt32 *a_pSize)
{
    OpcUa_Byte uadpVersionFlags;
    OpcUa_Byte extendedFlags1;
    OpcUa_Byte extendedFlags2;
    OpcUa_UadpDeclare_Context;

    OpcUa_InitializeStatus(OpcUa_Module_PubSub, "OpcUa_UadpNetworkMessageHeader_WriteBinary");

    OpcUa_UadpInit_Context;

    OpcUa_ReturnErrorIfArgumentNull(a_pValue);
    OpcUa_ReturnErrorIfArgumentNull(a_pBuffer);
    OpcUa_ReturnErrorIfArgumentNull(*a_pBuffer);
    OpcUa_ReturnErrorIfArgumentNull(a_pSize);


    /* assign the configured part of the flag bytes */
    uadpVersionFlags = (OpcUa_Byte)a_pValue->NetworkMessageFlags & 0x60; /* Take Byte 0 only */
    /* Bit 0-3: UADP Version, Bit 5: GroupHeader enabled, Bit 6: PayloadHeader enabled */
    uadpVersionFlags |= OPCUA_UADP_VERSION & 0x0F;

    extendedFlags1 = (OpcUa_Byte)((a_pValue->NetworkMessageFlags & 0x7800) >> 8); /* Take Byte 1 only */
    /* Bit 3: DataSetClassId enabled, Bit 4: Security enabled, Bit 5: Timestamp enabled, Bit 6: PicoSeconds enabled */
    extendedFlags2 = (OpcUa_Byte)((a_pValue->NetworkMessageFlags & 0x1F0000) >> 16); /* Take Byte 2 only */
    /* Bit 0: Chunk message, Bit 1: PromotedFields enabled */
    /* ExtendedFlags2 Bit 2-4 NetworkMessageType: 000: DataSetMessage, 001: Discovery Request, 010: Discovery Response */

    /* calculate the remaining bits */
    /* ExtendedFlags1 Bit 0-2 PublisherIdType: */
    if(a_pValue->PublisherId.ArrayType != OpcUa_VariantArrayType_Scalar)
    {
        OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError);
    }
    switch(a_pValue->PublisherId.Datatype)
    {
    case OpcUaType_Byte:
        /* 0x0 */
        uadpVersionFlags |= 0x10; /* PublisherId enabled */
        break;
    case OpcUaType_UInt16:
        extendedFlags1 |= 0x1;
        uadpVersionFlags |= 0x10; /* PublisherId enabled */
        break;
    case OpcUaType_UInt32:
        extendedFlags1 |= 0x2;
        uadpVersionFlags |= 0x10; /* PublisherId enabled */
        break;
    case OpcUaType_UInt64:
        extendedFlags1 |= 0x3;
        uadpVersionFlags |= 0x10; /* PublisherId enabled */
        break;
    case OpcUaType_String:
        extendedFlags1 |= 0x4;
        uadpVersionFlags |= 0x10; /* PublisherId enabled */
        break;
    case OpcUaType_Null:
        /* keep PublisherId disabled */
        break;
    default:
        /* unsupported data type */
        OpcUa_GotoErrorWithStatus(OpcUa_BadEncodingError);
        break;
    }

    /* ExtendedFlags1 Bit 7 ExtendedFlags2 enabled: */
    if(extendedFlags2)
    {
        extendedFlags1 |= 0x80;
    }

    /* UADPFlags Bit 7 ExtendedFlags1 enabled */
    if(extendedFlags1)
    {
        uadpVersionFlags |= 0x80;
    }

    OpcUa_UadpEncode_Direct(Byte, &uadpVersionFlags);
    if(extendedFlags1)
    {
        OpcUa_UadpEncode_Direct(Byte, &extendedFlags1);
    }
    if(extendedFlags2)
    {
        OpcUa_UadpEncode_Direct(Byte, &extendedFlags2);
    }

    /* cast away the const pointer */
    switch(a_pValue->PublisherId.Datatype)
    {
    case OpcUaType_Byte:
        OpcUa_UadpEncode_Direct(Byte, &a_pValue->PublisherId.Value.Byte);
        break;
    case OpcUaType_UInt16:
        OpcUa_UadpEncode_Direct(UInt16, &a_pValue->PublisherId.Value.UInt16);
        break;
    case OpcUaType_UInt32:
        OpcUa_UadpEncode_Direct(UInt32, &a_pValue->PublisherId.Value.UInt32);
        break;
    case OpcUaType_UInt64:
        OpcUa_UadpEncode_Direct(UInt64, &a_pValue->PublisherId.Value.UInt64);
        break;
    case OpcUaType_String:
        OpcUa_UadpEncode_Simple(String, &a_pValue->PublisherId.Value.String);
        break;
    case OpcUaType_Null:
        break;
    }

    if(a_pValue->NetworkMessageFlags & OpcUa_UadpNetworkMessageFlags_DataSetClassId)
    {
        OpcUa_UadpEncode_Simple(Guid, &a_pValue->DataSetClassId);
    }

    OpcUa_UadpClear_Context;

    OpcUa_ReturnStatusCode;
    OpcUa_BeginErrorHandling;

    OpcUa_UadpClear_Context;

    OpcUa_FinishErrorHandling;
}