HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::SecureConnect___STATIC__VOID__I4__STRING__OBJECT( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_INT32 sslContext     = stack.Arg0().NumericByRef().s4;
    CLR_RT_HeapBlock* hb     = stack.Arg1().DereferenceString();
    CLR_RT_HeapBlock* socket = stack.Arg2().Dereference();
    CLR_INT32         timeout_ms = -1; // wait forever
    CLR_RT_HeapBlock  hbTimeout;
    
    int        result;    
    LPCSTR     szName;
    CLR_INT32  handle;
    bool       fRes = true;
    CLR_INT64 *timeout;

    FAULT_ON_NULL(socket);

    handle = socket[ Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::FIELD__m_Handle ].NumericByRef().s4;

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    FAULT_ON_NULL_ARG(hb);

    szName = hb->StringText();

    hbTimeout.SetInteger( timeout_ms );
        
    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    while(true)
    {
        result = SSL_Connect( handle, szName, sslContext );

        if(result == SOCK_EWOULDBLOCK || result == SOCK_TRY_AGAIN)
        {
            // non-blocking - allow other threads to run while we wait for socket activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));

            if(result < 0) break;
        }
        else
        {
            break;
        }
    }

    stack.PopValue();       // Timeout

    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::UpdateCertificates___STATIC__VOID__I4__MicrosoftSPOTNativeSystemSecurityCryptographyX509CertificatesX509Certificate__SZARRAY_MicrosoftSPOTNativeSystemSecurityCryptographyX509CertificatesX509Certificate( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_INT32               sslContext = stack.Arg0().NumericByRef().s4;
    CLR_RT_HeapBlock*       hbCert     = stack.Arg1().Dereference(); 
    CLR_RT_HeapBlock_Array* arrCA      = stack.Arg2().DereferenceArray(); 
    CLR_RT_HeapBlock_Array* arrCert;
    CLR_UINT8* sslCert;
    int        i;
    CLR_RT_HeapBlock*       hbPwd;
    LPCSTR  szPwd;

    FAULT_ON_NULL(hbCert);
    FAULT_ON_NULL(arrCA);

    arrCert    = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_certificate ].DereferenceArray(); FAULT_ON_NULL(arrCert);

    sslCert    = arrCert->GetFirstElement();

    hbPwd      = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_password ].Dereference(); FAULT_ON_NULL(hbPwd);

    szPwd      = hbPwd->StringText();
    
    SSL_ClearCertificateAuthority( sslContext );

    if(!SSL_AddCertificateAuthority( sslContext, (const char*)sslCert, arrCert->m_numOfElements, szPwd )) TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);

    for(i=0; i<(int)arrCA->m_numOfElements; i++)
    {
        hbCert = (CLR_RT_HeapBlock*)arrCA->GetElement( i ); FAULT_ON_NULL(arrCert);

        arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_certificate ].DereferenceArray();

        sslCert = arrCert->GetFirstElement();

        hbPwd      = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_password ].Dereference();
        
        szPwd      = hbPwd->StringText();
        
        if(!SSL_AddCertificateAuthority( sslContext, (const char*)sslCert, arrCert->m_numOfElements, szPwd )) TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);
    }

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::InitHelper( CLR_RT_StackFrame& stack, bool isServer )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_INT32 sslContext            = -1;
    CLR_INT32 sslMode               = stack.Arg0().NumericByRef().s4;
    CLR_INT32 sslVerify             = stack.Arg1().NumericByRef().s4;
    CLR_RT_HeapBlock *hbCert        = stack.Arg2().Dereference(); 
    CLR_RT_HeapBlock_Array* arrCA   = stack.Arg3().DereferenceArray(); 
    CLR_RT_HeapBlock_Array* arrCert = NULL;
    CLR_UINT8*  sslCert             = NULL;
    int         result;
    int         i;
    bool        isFirstCall = false;
    LPCSTR      szPwd = "";

    if(!g_SSL_SeedData.Initialized)
    {
        BOOL fOK = FALSE;

        isFirstCall = true;

#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE)
        int i;

        if(!HAL_CONFIG_BLOCK::ApplyConfig( g_SSL_SeedData.Config.GetDriverName(), &g_SSL_SeedData.Config, sizeof(g_SSL_SeedData.Config) ))
        {
            return CLR_E_NOT_SUPPORTED;
        }

        // validate the security key (make sure it isn't all 0x00 or all 0xFF
        for(i=1; i<sizeof(g_SSL_SeedData.Config.SslSeedKey) && !fOK; i++)
        {
            if( g_SSL_SeedData.Config.SslSeedKey[ i   ] != 0 && 
                g_SSL_SeedData.Config.SslSeedKey[ i   ] != 0xFF && 
                g_SSL_SeedData.Config.SslSeedKey[ i-1 ] != g_SSL_SeedData.Config.SslSeedKey[ i ])
            {
                fOK = TRUE;
            }
        }

        if(!fOK)
        {
            return CLR_E_NOT_SUPPORTED;
        }
#endif

        g_SSL_SeedData.m_completion.Initialize();
        
        g_SSL_SeedData.m_completion.InitializeForUserMode( UpdateSslSeedValue, NULL ); 

        g_SSL_SeedData.Initialized = TRUE;
    }


    if(hbCert != NULL)
    {
        arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_certificate ].DereferenceArray(); //FAULT_ON_NULL(arrCert);

        // If arrCert == NULL then the certificate is an X509Certificate2 which uses a certificate handle
        if(arrCert == NULL)
        {
            arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_handle ].DereferenceArray(); FAULT_ON_NULL(arrCert);    

            // pass the certificate handle as the cert data parameter
            sslCert = arrCert->GetFirstElement();

            arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_sessionHandle ].DereferenceArray(); FAULT_ON_NULL(arrCert);    

            // pass the session handle as the ssl context parameter
            sslContext = *(INT32*)arrCert->GetFirstElement();

            // the certificate has already been loaded so just pass an empty string
            szPwd = "";
        }
        else
        {
            arrCert->Pin();
        
            sslCert = arrCert->GetFirstElement();

            CLR_RT_HeapBlock *hbPwd = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_password ].Dereference();// FAULT_ON_NULL(hbPwd);

            szPwd = hbPwd->StringText();
        }
    }

    SSL_RegisterTimeCallback( Time_GetDateTime );

    if(isServer)
    {
        result = (SSL_ServerInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, szPwd, sslContext ) ? 0 : -1);
    }
    else
    {
        result = (SSL_ClientInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, szPwd, sslContext ) ? 0 : -1);
    }

    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));

    if(isFirstCall)
    {
        GenerateNewSslSeed();
    }

    if(arrCA != NULL)
    {
        for(i=0; i<(int)arrCA->m_numOfElements; i++)
        {
            hbCert = (CLR_RT_HeapBlock*)arrCA->GetElement( i ); FAULT_ON_NULL(hbCert);
            hbCert = hbCert->Dereference();                     FAULT_ON_NULL(hbCert);

            arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_certificate ].DereferenceArray(); //FAULT_ON_NULL(arrCert);

            // If arrCert == NULL then the certificate is an X509Certificate2 which uses a certificate handle
            if(arrCert == NULL)
            {
                CLR_INT32 sessionCtx = 0;

                arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_handle ].DereferenceArray(); FAULT_ON_NULL(arrCert);    

                sslCert = arrCert->GetFirstElement();

                arrCert = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_sessionHandle ].DereferenceArray(); FAULT_ON_NULL(arrCert);    

                sessionCtx = *(INT32*)arrCert->GetFirstElement();

                // pass the session handle down as the password paramter and the certificate handle as the data parameter
                result = (SSL_AddCertificateAuthority( sslContext, (const char*)sslCert, arrCert->m_numOfElements, (LPCSTR)&sessionCtx ) ? 0 : -1);
                
                TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));
            }
            else
            {

                arrCert->Pin();

                sslCert = arrCert->GetFirstElement();

                CLR_RT_HeapBlock *hbPwd = hbCert[ Library_spot_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD__m_password ].Dereference(); FAULT_ON_NULL(hbPwd);

                LPCSTR szCAPwd = hbPwd->StringText();
                
                result = (SSL_AddCertificateAuthority( sslContext, (const char*)sslCert, arrCert->m_numOfElements, szCAPwd ) ? 0 : -1);
                
                TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));
            }
        }
    }

    stack.SetResult_I4( sslContext );    

    TINYCLR_CLEANUP();

    if(FAILED(hr) && (sslContext != -1))
    {
        SSL_ExitContext( sslContext );        
    }

    TINYCLR_CLEANUP_END();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::ParseCertificate___STATIC__VOID__SZARRAY_U1__STRING__BYREF_STRING__BYREF_STRING__BYREF_mscorlibSystemDateTime__BYREF_mscorlibSystemDateTime( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock_Array* arrData    = stack.Arg0().DereferenceArray(); 
    CLR_UINT8*              certBytes;
    CLR_RT_HeapBlock        hbIssuer;
    CLR_RT_HeapBlock        hbSubject;
    CLR_RT_ProtectFromGC    gc1( hbIssuer  );
    CLR_RT_ProtectFromGC    gc2( hbSubject );
    X509CertData            cert;
    CLR_INT64*              val;
    CLR_INT64               tzOffset;
    SYSTEMTIME              st;
    INT32                   standardBias;
    CLR_RT_HeapBlock*       hbPwd     = stack.Arg1().DereferenceString();
    LPCSTR                  szPwd;


    FAULT_ON_NULL_ARG(hbPwd);

    szPwd = hbPwd->StringText();

    CLR_RT_Memory::ZeroFill( &cert, sizeof(cert) );

    FAULT_ON_NULL(arrData);

    certBytes = arrData->GetFirstElement();

    if(!SSL_ParseCertificate( (const char*)certBytes, arrData->m_numOfElements, szPwd, &cert )) TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);

    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbIssuer, cert.Issuer ));
    TINYCLR_CHECK_HRESULT(hbIssuer.StoreToReference( stack.Arg2(), 0 ));

    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbSubject, cert.Subject ));
    TINYCLR_CHECK_HRESULT(hbSubject.StoreToReference( stack.Arg3(), 0 ));

    st.wYear         = cert.EffectiveDate.year;
    st.wMonth        = cert.EffectiveDate.month;
    st.wDay          = cert.EffectiveDate.day;
    st.wHour         = cert.EffectiveDate.hour;
    st.wMinute       = cert.EffectiveDate.minute;
    st.wSecond       = cert.EffectiveDate.second;
    st.wMilliseconds = cert.EffectiveDate.msec;

    standardBias     = Time_GetTimeZoneOffset();
    standardBias    *= TIME_CONVERSION__ONEMINUTE;

    val = Library_corlib_native_System_DateTime::GetValuePtr( stack.Arg4() );
    *val = Time_FromSystemTime( &st );

    tzOffset = cert.EffectiveDate.tzOffset;

    // adjust for timezone differences
    if(standardBias != tzOffset)
    {
        *val += tzOffset - standardBias; 
    }

    st.wYear         = cert.ExpirationDate.year;
    st.wMonth        = cert.ExpirationDate.month;
    st.wDay          = cert.ExpirationDate.day;
    st.wHour         = cert.ExpirationDate.hour;
    st.wMinute       = cert.ExpirationDate.minute;
    st.wSecond       = cert.ExpirationDate.second;
    st.wMilliseconds = cert.ExpirationDate.msec;
    
    val = Library_corlib_native_System_DateTime::GetValuePtr( stack.ArgN( 5 ) );
    *val = Time_FromSystemTime( &st );

    tzOffset = cert.ExpirationDate.tzOffset;
    
    if(standardBias != tzOffset)
    {
       *val += tzOffset - standardBias; 
    }

    TINYCLR_NOCLEANUP();
}