/*============================================================================
 * OpcUa_Signature_Initialize
 *===========================================================================*/
OpcUa_Void OPCUA_DLLCALL OpcUa_Signature_Initialize(OpcUa_Signature* a_pSignature)
{
    OpcUa_ByteString_Initialize(&a_pSignature->Signature);
    a_pSignature->Algorithm = 0;
}
/*============================================================================
 * 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_Key_Initialize
 *===========================================================================*/
OpcUa_Void OpcUa_Key_Initialize(OpcUa_Key* a_pKey)
{
    OpcUa_ByteString_Initialize(&a_pKey->Key);
    a_pKey->Type = 0;
    a_pKey->fpClearHandle = OpcUa_Null;
}