Hello, I tested your small program and it seems to work properly, which, I suppose, means that the problem resides in my client code. I copy-pasted the output below.
I just find something strange on the server : to write my server code, I followed a tuto where they initialised a diffie-helman key in the server side. I was not sure of the utility of that and thus, I performed several tests with the command you provided : with and without this initialisation on the server side. In both cases, this works properly. So, I am a little bit confused about that. I would want to remove that part, but I am not sure if it may be useful... I joined my client code. The interesting function is "wxSSLSocketClient::InitiateSSLSession". This code uses the wxWidgets library and thus, it uses the wxSocketClient (wxWidgets socket implementation) with a dedicated BIO so that openssl can handle it. This code is extracted from the wxEMail project (I am the maintaniner of this project). But, in this project, I did not implement the server certificate check stuff. Thus, this version is slighlty modified to perform those additional checks. You will easily identify which part is original code and which one is not because original code was designed to work in static link as well as dynamic link (with a manual load of library). So, in original code, all ssl calls are encapsulated in a macro. The modified version currenlty only support static link, and thus ssl calls are not encapsulated in the macro. Note that this code allows performing ssl connection on different servers and thus, I really think that the BIO part and so on is OK. The only part that has never been tested is the new part performing the server certificate check. Thanks for your help. Regards, Brice D:\home\DbSync1>C:\OpenSSL-Win32\bin\openssl s_client -connect localhost:1212 -C Afile server.crt Loading 'screen' into random state - done CONNECTED(00000738) depth=0 C = BE, ST = Hainaut, L = Charleroi, O = AMS-Solutions, CN = Brice Andre , emailAddress = brice.an...@xxx.be verify return:1 --- Certificate chain 0 s:/C=BE/ST=Hainaut/L=Charleroi/O=AMS-Solutions/CN=Brice Andre/emailAddress=br ice.an...@xxx.be i:/C=BE/ST=Hainaut/L=Charleroi/O=AMS-Solutions/CN=Brice Andre/emailAddress=br ice.an...@xxx.be --- Server certificate -----BEGIN CERTIFICATE----- MIIDnDCCAoQCCQDc4fMRV+0qfzANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMC QkUxEDAOBgNVBAgTB0hhaW5hdXQxEjAQBgNVBAcTCUNoYXJsZXJvaTEWMBQGA1UE ChMNQU1TLVNvbHV0aW9uczEUMBIGA1UEAxMLQnJpY2UgQW5kcmUxKzApBgkqhkiG 9w0BCQEWHGJyaWNlLmFuZHJlQGFtcy1zb2x1dGlvbnMuYmUwIBcNMTMwNTI2MDUw MzUyWhgPMjA2ODAyMjcwNTAzNTJaMIGOMQswCQYDVQQGEwJCRTEQMA4GA1UECBMH SGFpbmF1dDESMBAGA1UEBxMJQ2hhcmxlcm9pMRYwFAYDVQQKEw1BTVMtU29sdXRp b25zMRQwEgYDVQQDEwtCcmljZSBBbmRyZTErMCkGCSqGSIb3DQEJARYcYnJpY2Uu YW5kcmVAYW1zLXNvbHV0aW9ucy5iZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKEDpEF1+IOPim2EPvgVjOtdnSal4UjSdl1Bg2dTpGWZpUAwacoCT7kB sTwkGqgSHs/3Zt171oa14qZrBequpjcMCKOD/JLsMYNZaJLIhLIMHUbNiq0xEIeu dwy81MhwzKIKm/4SAta++x6/wLVGsgJ+GgLMEs7oDpAVgiOot1xV4SEUfsanrl8e QQkjP43pPTtWbdDsTZ4XKl2LStH5hFVnYAC7Y6KEbZJvkqcfMG92mSsOR/4JrSWe 0WtjBjoDhkPxnmlpuFkyfk5EFep5/Qg7Ut+fi0k4/9O28POXbFEwnstDqTbSJdsN N0C665u9167J+AmkeZ3n7z41HGgB1TcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA K7t53eIY+rMjyCk9IDtcD+SUDa4AltuVcSq0xADzjjtH+11QQvI4/l20eDBV/bnm HpbNZP2Z8jBnbrCn7bEOqY1HzQrc9KBipy+kbNHknq1MzcteB6b1qIOgr92A0e6A qVqaULuXKsIj0Ot/g6eh//e4IBJGOg+kbSpB3mDO9G9utP3W8KB7leUDmsBRW1ld tQ4wtmqknr1WZSXkxa4JDFDBwP6DWymbSl0S7xQO9/5kPWIubL77FxxUZ73jC/G+ iz+rAM2LrqN3Lppp3aH7gkH9pKTWciE7f8kEHfSUKU7LQ87bood0R8XOTvE5xuJq lJSl3bu6XXt/u/ZibObTyw== -----END CERTIFICATE----- subject=/C=BE/ST=Hainaut/L=Charleroi/O=AMS-Solutions/CN=Brice Andre/emailAddress =brice.an...@xxx.be issuer=/C=BE/ST=Hainaut/L=Charleroi/O=AMS-Solutions/CN=Brice Andre/emailAddress= brice.an...@xxx.be --- No client certificate CA names sent --- SSL handshake has read 1774 bytes and written 519 bytes --- New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : DHE-RSA-AES256-SHA Session-ID: 6F265E53749453BE5C3DD2BFFF4B99A1DBDA559AF76E8C8974A90ABEEED34AF1 Session-ID-ctx: Master-Key: 142C4C0BA297D034922C619C9C6EF658D66C476386CE0FECD502B3B990FD01BE FA3C6B067055860A7BD8632B69E49810 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None TLS session ticket: 0000 - 86 89 a4 c4 44 8f a9 e4-0d 76 5f 7e 95 3c 3d aa ....D....v_~.<=. 0010 - 05 4b f0 33 bc 09 7e 08-42 0d f6 81 41 52 81 62 .K.3..~.B...AR.b 0020 - 0f cc 2d de 32 84 b2 57-28 fc c3 2c cc 4b 26 42 ..-.2..W(..,.K&B 0030 - 8b f0 8e 99 37 8e fb 63-50 fe ee c6 10 b1 37 da ....7..cP.....7. 0040 - 90 1c 03 ad cb 08 db ff-93 dc 40 1c a1 7a e1 43 ..........@..z.C 0050 - f2 fc d2 3d 86 46 9a 88-d6 6f 25 62 aa 59 41 a9 ...=.F...o%b.YA. 0060 - a6 29 45 dc 47 3b a9 2f-60 bb 34 d2 42 74 d7 48 .)E.G;./`.4.Bt.H 0070 - d7 82 71 66 d5 5c 1d fb-84 86 10 93 d9 59 d1 cd ..qf.\.......Y.. 0080 - 72 ac be d8 bc af 23 a1-00 90 a7 4b 68 ef 58 69 r.....#....Kh.Xi 0090 - f5 e7 75 b0 be 33 d4 19-d8 e0 81 b4 b8 37 bc 79 ..u..3.......7.y Start Time: 1369897977 Timeout : 300 (sec) Verify return code: 0 (ok) --- 2013/5/29 Dave Thompson <dthomp...@prinpay.com>: >> From: owner-openssl-us...@openssl.org On Behalf Of Brice André >> Sent: Wednesday, 29 May, 2013 03:14 > >> I performed a test yesterday with the instruction >> SSL_CTX_use_certificate_file(tx,path_to_file, SSL_FILETYPE_PEM); >> replaced by >> SSL_CTX_load_verify_locations(ctx, path_to_file, NULL); >> >> Where path_to_file points to my file "server.crt". The function >> returns 1 so, I expect my certificate to be properly initialised. >> > To be exact, the client's trustore containing your cert. > > One possible problem here: _load_verify_ accepts a sequence of > (PEM) certs, including zero, skipping any invalid format(s). > Make sure the client's file is/contains an exact copy of the > server's certfile, at least the lines from dash-BEGIN to dash-END, > including eol (either NL or CRLF okay) after each line (including > the dash-END line) and body lines not longer than 76 characters. > If you copied the content by cut-and-paste or sending in an email > or something like that, these sometimes go wrong. If you transferred > the file using FTP or SCP or similar, they shouldn't. (FTP mode A > may convert but not add/delete/move eols, and that is okay.) > >> But, whn I perform the connect, I get an error. The corresponding >> error message is : >> error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate >> verify failed >> >> After the connect failed, the function SSL_get_peer_certificate(ssl) >> returns NULL and the function SSL_get_verify_result(ssl) returns 18 >> (X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT), which is exactly the same >> problem as before. >> > It should work and does for me, as long as the client CAfile is > exactly the (selfsigned) cert the server is using; and you don't have > KeyUsage excluding certSign, but that gives a different error. > > If it isn't damaged per above and you have commandline on the client try > openssl s_client -connect host:port -CAfile same.server.crt.file > and see what it says for Verify return code at the end of SSL-session > (note s_client unlike a real app will proceed even if verify error). > >> My server is also printing an error message: >> error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca >> > That's consistent; if the client decides the server cert is bad, > the client aborts the handshake with an alert like that. > (The exact alert may vary SSL vs TLS, but always some alert.) > > ______________________________________________________________________ > OpenSSL Project http://www.openssl.org > User Support Mailing List openssl-users@openssl.org > Automated List Manager majord...@openssl.org
//////////////////////////////////////////////////////////////////////////// // Name: wxSSLSocketClient.cpp // Purpose: This class implements the wxSSLSocketClient // Author: Brice Andr� // Created: 2011/01/25 // RCS-ID: $Id: mycomp.cpp 505 2007-03-31 10:31:46Z frm $ // Copyright: (c) 2011 Brice Andr� // Licence: wxWidgets licence ///////////////////////////////////////////////////////////////////////////// #ifdef OPEN_SSL_STATIC_LINK #define CALL_SSL(lib,func) func #else #define CALL_SSL(lib,func) lib.func #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif // includes #ifndef WX_PRECOMP // here goes the #include <wx/abc.h> directives for those // files which are not included by wxprec.h #endif #include <wx/ssl/wxSSLSocketClient.h> wxSSLSocketClient::OpenSslInitialisator::OpenSslInitialisator() { /* We perform a lazy load of lib so that it does not fail if openssl lib could not be loaded in case it is not requested */ lib_is_initialised = false; } wxSSLSocketClient::OpenSslInitialisator::~OpenSslInitialisator() { } const wxSSLSocketClient::OpenSslInitialisator::LibIf_t& wxSSLSocketClient::OpenSslInitialisator::GetLibIf() { /* Check if lib was already loaded */ if (!lib_is_initialised) { #ifndef OPEN_SSL_STATIC_LINK /* load the library */ if (!ssl_lib.Load(wxT("ssleay32"))) { throw Exception(wxT("Unable to load ssleay32 dynamic library")); } if (!lib_eay.Load(wxT("libeay32"))) { throw Exception(wxT("Unable to load libeay32 dynamic library")); } /* Initialise the library */ ((void(*)(void))LoadSymbol(ssl_lib, wxT("SSL_load_error_strings"), wxT("ssleay32")))(); ((void(*)(void))LoadSymbol(ssl_lib, wxT("SSL_library_init"), wxT("ssleay32")))(); /* Initialise all requested symbols */ lib_if.SSLv23_client_method = (const SSL_METHOD*(*)(void))LoadSymbol(ssl_lib, wxT("SSLv23_client_method"), wxT("ssleay32")); lib_if.SSL_CTX_new = (SSL_CTX*(*)(const SSL_METHOD*))LoadSymbol(ssl_lib, wxT("SSL_CTX_new"), wxT("ssleay32")); lib_if.SSL_CTX_free = (void(*)(SSL_CTX*))LoadSymbol(ssl_lib, wxT("SSL_CTX_free"), wxT("ssleay32")); lib_if.SSL_CTX_ctrl = (long(*)(SSL_CTX*, int,long,void*))LoadSymbol(ssl_lib, wxT("SSL_CTX_ctrl"), wxT("ssleay32")); lib_if.SSL_new = (SSL*(*)(SSL_CTX*))LoadSymbol(ssl_lib, wxT("SSL_new"), wxT("ssleay32")); lib_if.SSL_free = (void (*)(SSL*))LoadSymbol(ssl_lib, wxT("SSL_free"), wxT("ssleay32")); lib_if.SSL_set_cipher_list = (int(*)(SSL*,const char*))LoadSymbol(ssl_lib, wxT("SSL_set_cipher_list"), wxT("ssleay32")); lib_if.SSL_set_bio = (void(*)(SSL*,BIO*,BIO*))LoadSymbol(ssl_lib, wxT("SSL_set_bio"), wxT("ssleay32")); lib_if.SSL_set_connect_state = (void(*)(SSL*))LoadSymbol(ssl_lib, wxT("SSL_set_connect_state"), wxT("ssleay32")); lib_if.SSL_connect = (int(*)(SSL*))LoadSymbol(ssl_lib, wxT("SSL_connect"), wxT("ssleay32")); lib_if.SSL_shutdown = (int(*)(SSL*))LoadSymbol(ssl_lib, wxT("SSL_shutdown"), wxT("ssleay32")); lib_if.SSL_read = (int(*)(SSL*,void*,int))LoadSymbol(ssl_lib, wxT("SSL_read"), wxT("ssleay32")); lib_if.SSL_write = (int(*)(SSL*,const void*,int))LoadSymbol(ssl_lib, wxT("SSL_write"), wxT("ssleay32")); lib_if.SSL_get_error = (int(*)(const SSL *ssl, int ret))LoadSymbol(ssl_lib, wxT("SSL_get_error"), wxT("ssleay32")); lib_if.BIO_new = (BIO*(*)(BIO_METHOD*))LoadSymbol(lib_eay, wxT("BIO_new"), wxT("libeay32")); lib_if.BIO_free = (int(*)(BIO*))LoadSymbol(lib_eay, wxT("BIO_free"), wxT("libeay32")); lib_if.ERR_get_error = (unsigned long(*)(void))LoadSymbol(lib_eay, wxT("ERR_get_error"), wxT("libeay32")); lib_if.ERR_error_string = (char*(*)(unsigned long e, char *buf))LoadSymbol(lib_eay, wxT("ERR_error_string"), wxT("libeay32")); #else SSL_load_error_strings(); SSL_library_init(); #endif lib_is_initialised = true; } return lib_if; } void* wxSSLSocketClient::OpenSslInitialisator::LoadSymbol(wxDynamicLibrary& lib, const wxString& name, const wxString& lib_name) { void* result = lib.GetSymbol(name); if (result == NULL) { throw Exception(wxString::Format(_("Unable to load symbol \"%s\" from library \"%s\""), name.fn_str(), lib_name.fn_str())); } return result; } wxSSLSocketClient::wxSSLSocketClient(wxSocketFlags flags, bool check_certificate, const wxString& certificate_file) :wxSocketClient(flags), connection_state(NoSslConnectionState), check_certificate(check_certificate), certificate_file(certificate_file) { /* configure internal stuff */ ctx = NULL; ssl = NULL; bio = NULL; last_ssl_count = 0; ssl_error = true; } wxSSLSocketClient::~wxSSLSocketClient() { /* Check if we are currently in SSL connection */ if (connection_state != NoSslConnectionState) { /* We shall first switch to blocking mode because, if object is destroyed during * wxWidgets cleanup, no more event loop is running */ //TODO : note that if we detect that we are in cleanup phase, we could avoid configuring socket in // blocking mode when not requested... SetFlags(wxSOCKET_WAITALL|wxSOCKET_BLOCK); /* Now, we can safely cleanup socket stuff */ TerminateSSLSession(); } } wxSSLSocketClient::SslSessionStatus_t wxSSLSocketClient::InitiateSSLSession() { /* Check if we are not already in SSL session */ if (connection_state == SslConnectedState) { /* We are already in SSL session... */ return SslFailed; } /* Get lib info */ const OpenSslInitialisator::LibIf_t& ssl_lib = open_ssl_initialisator.GetLibIf(); /* Check if connection is pending */ if (connection_state == NoSslConnectionState) { /* Configure ssl context */ ctx = CALL_SSL(ssl_lib,SSL_CTX_new)(CALL_SSL(ssl_lib,SSLv23_client_method)()); //ssl_lib.SSL_CTX_ctrl(ctx,SSL_CTRL_OPTIONS,SSL_OP_ALL,NULL); /* Check if we shall request server authentication */ if (check_certificate) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); int res = SSL_CTX_load_verify_locations(ctx, certificate_file.mb_str().data(), NULL); wxLogDebug("Function returned %d", res); } /* Create SSL connection */ ssl = CALL_SSL(ssl_lib,SSL_new)(ctx); if (ssl != NULL) { /* Configure cypher algorithms supported */ CALL_SSL(ssl_lib,SSL_set_cipher_list)(ssl, "ALL"); bio = CALL_SSL(ssl_lib,BIO_new)(SslBio::GetBio()); bio->ptr = this; CALL_SSL(ssl_lib,SSL_set_bio)(ssl,bio,bio); CALL_SSL(ssl_lib,SSL_set_connect_state)(ssl); } else { /* Release context */ CALL_SSL(ssl_lib,SSL_CTX_free)(ctx); ctx = NULL; /* Return error status */ return SslFailed; } } /* Try connection */ int ret = CALL_SSL(ssl_lib,SSL_connect)(ssl); if (ret <= 0) { /* check if we are just in a retry mode */ int error = CALL_SSL(ssl_lib,SSL_get_error)(ssl, ret); if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { /* mark connection as pending */ connection_state = SsConnectionPendingState; return SslPending; } else { /* Try to get some info */ char msg[65535]; ERR_error_string_n(ERR_get_error(), msg, 65535); wxString error_message = wxString::Format("Error: %s (got certificate : %s, error id %d)\n\n", msg, SSL_get_peer_certificate(ssl)==NULL?"false":"true", SSL_get_verify_result(ssl)); wxLogDebug(error_message); /* Release connection*/ CALL_SSL(ssl_lib,SSL_free)(ssl); ssl = NULL; /* Release context */ CALL_SSL(ssl_lib,SSL_CTX_free)(ctx); ctx = NULL; /* reset connection state */ connection_state = NoSslConnectionState; return SslFailed; } } /* check certificate stuff */ if (check_certificate) { int error = SSL_get_verify_result(ssl); wxLogDebug("Error : %d", error); if ((SSL_get_peer_certificate(ssl) == NULL) || ((SSL_get_verify_result(ssl) != X509_V_OK) && (SSL_get_verify_result(ssl) != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) && (SSL_get_verify_result(ssl) != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))) { //TODO : on ne peut pas faire comme ça : une fois ce check raté, les autres ne sont plus faits!!! if (SSL_get_peer_certificate(ssl) == NULL) { wxLogDebug("Certificate not received !"); } else { wxLogDebug("Could not validate received certificate !"); } return SslCertificateNotChecked; } } /* We are properly connected */ connection_state = SslConnectedState; return SslConnected; } bool wxSSLSocketClient::TerminateSSLSession() { /* check if we are connected */ if (connection_state == NoSslConnectionState) { return false; } /* Get lib info */ const OpenSslInitialisator::LibIf_t& ssl_lib = open_ssl_initialisator.GetLibIf(); /* Close session */ CALL_SSL(ssl_lib,SSL_shutdown)(ssl); /* Release connection*/ CALL_SSL(ssl_lib,SSL_free)(ssl); ssl = NULL; /* Release context */ CALL_SSL(ssl_lib,SSL_CTX_free)(ctx); ctx = NULL; /* Mark as no ssl */ connection_state = NoSslConnectionState; /* We are now properly disconnected from SSL session */ return true; } bool wxSSLSocketClient::IsInSSLSession() const { return connection_state == SslConnectedState; } bool wxSSLSocketClient::SslSessionPending() const { return connection_state == SsConnectionPendingState; } wxSSLSocketClient& wxSSLSocketClient::Read(void* buffer, wxUint32 nbytes) { /* check if we are in ssl mode */ if (connection_state == SslConnectedState) { /* Perform a SSL read */ int nb_bytes_read = CALL_SSL(open_ssl_initialisator.GetLibIf(),SSL_read)(ssl, buffer, nbytes); if (nb_bytes_read < 0) { last_ssl_count = 0; ssl_error = true; } else { last_ssl_count = nb_bytes_read; ssl_error = false; } } else if (connection_state == NoSslConnectionState) { /* perform a normal read */ wxSocketClient::Read(buffer, nbytes); } else { last_ssl_count = 0; ssl_error = true; } return *this; } wxSSLSocketClient& wxSSLSocketClient::Write(const void *buffer, wxUint32 nbytes) { /* check if we are in ssl mode */ if (connection_state == SslConnectedState) { /* Perform a SSL read */ int nb_bytes_written = CALL_SSL(open_ssl_initialisator.GetLibIf(),SSL_write)(ssl, buffer, nbytes); if (nb_bytes_written < 0) { last_ssl_count = 0; ssl_error = true; } else { last_ssl_count = nb_bytes_written; ssl_error = false; } } else if (connection_state == NoSslConnectionState) { /* perform a normal read */ wxSocketClient::Write(buffer, nbytes); } else { last_ssl_count = 0; ssl_error = true; } return *this; } wxSSLSocketClient& wxSSLSocketClient::BasicRead(void* buffer, wxUint32 nbytes) { return (wxSSLSocketClient&)wxSocketClient::Read(buffer, nbytes); } wxSSLSocketClient& wxSSLSocketClient::BasicWrite(const void *buffer, wxUint32 nbytes) { return (wxSSLSocketClient&)wxSocketClient::Write(buffer, nbytes); } wxUint32 wxSSLSocketClient::LastCount() const { if (connection_state != NoSslConnectionState) { return last_ssl_count; } else { return wxSocketClient::LastCount(); } } wxUint32 wxSSLSocketClient::BasicLastCount() const { return wxSocketClient::LastCount(); } bool wxSSLSocketClient::Error() const { if (connection_state != NoSslConnectionState) { return ssl_error; } else { return wxSocketClient::Error(); } } bool wxSSLSocketClient::BasicError() const { return wxSocketClient::Error(); } bool wxSSLSocketClient::Close() { if (IsInSSLSession()) { TerminateSSLSession(); } return wxSocketClient::Close(); } BIO_METHOD* wxSSLSocketClient::SslBio::GetBio() { static BIO_METHOD methods = { BIO_TYPE_SOCKET, "wxEmail Socket", Write, Read, Puts, Gets, Ctrl, Create, Destroy, NULL, }; return &methods; } int wxSSLSocketClient::SslBio::Write(BIO* bio, const char* buffer, int nbytes) { wxSSLSocketClient* ptr = (wxSSLSocketClient*)bio->ptr; ptr->BasicWrite(buffer, nbytes); if (ptr->BasicError()) { return -1; } else { return ptr->BasicLastCount(); } } int wxSSLSocketClient::SslBio::Read(BIO* bio, char* buffer, int nbytes) { wxSSLSocketClient* ptr = (wxSSLSocketClient*)bio->ptr; ptr->BasicRead(buffer, nbytes); if (ptr->BasicError()) { return -1; } else { return ptr->BasicLastCount(); } } int wxSSLSocketClient::SslBio::Puts(BIO*, const char*) { throw Exception(wxT("wxSSLSocketClient::SslBio::Puts : not implemented")); } int wxSSLSocketClient::SslBio::Gets(BIO*, char*, int) { throw Exception(wxT("wxSSLSocketClient::SslBio::Gets : not implemented")); } long wxSSLSocketClient::SslBio::Ctrl(BIO* WXUNUSED(bio), int WXUNUSED(ctrl), long WXUNUSED(arg), void* WXUNUSED(clbk)) { return 1; } int wxSSLSocketClient::SslBio::Create(BIO* bio) { bio->init=1; bio->num=-1; bio->ptr=NULL; bio->flags=0; return 1; } int wxSSLSocketClient::SslBio::Destroy(BIO* bio) { if (bio == NULL) { return 0; } if (bio->shutdown) { bio->init=0; bio->flags=0; } return 1; } wxSSLSocketClient::OpenSslInitialisator wxSSLSocketClient::open_ssl_initialisator;