SocketTlsHandshake

Initiieren einer sicheren (SSL) Verbindung mit einem angegebenen Host über das Protokoll des TLS-Handshakes. Während des Handshakes vereinbaren Client und Server die Verbindungsparameter: das zu verwendende Protokoll und die Verschlüsselungsmethode.

bool  SocketTlsHandshake(
   int           socket,               // Socket
   const string  host                  // Adresse des Hosts
   );

Parameter

socket

[in]  Das Handle des Sockets, das von der Funktion SocketCreate erzeugt worden war. Wurde ein ungültiges Handle erstellt, wird der Fehler 5270 (ERR_NETSOCKET_INVALIDHANDLE) der Variablen _LastError zugewiesen.

host

[in]  Adresse des Hosts, mit dem die sichere Verbindung hergestellt werden soll.

Rückgabewert

Gibt true im Erfolgsfall zurück, andernfalls false.

Hinweis

Vor einer sicheren Verbindung sollte das Programm eine standardmäßige TCP-Verbindung mit dem Host über SocketConnect aufbauen.

Kommt keine die sichere Verbindung zustande, wird der Fehler 5274 (ERR_NETSOCKET_HANDSHAKE_FAILED) der Variablen _LastError zugewiesen.

Es ist nicht notwendig, bei einer Verbindung zum Port 443 diese Funktion aufzurufen. Dies ist ein standardmäßiger TCP-Port, der für sichere (SSL) TLS-Verbindungen verwendet wird.

Die Funktion kann nur von Expert Advisors und Skripten aufgerufen werden, da sie in ihrem eigenen Ausführungsthread laufen. Wenn sie ein Indikator aufruft, wird von GetLastError() der Fehler 4014 – "Funktionsaufruf ist nicht erlaubt" ausgeworfen.

Beispiel:

//+------------------------------------------------------------------+
//|                                           SocketTlsHandshake.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com
#property version     "1.00"
 
#define   SERVER    "smtp.gmail.com"
#define   PORT      587
//+------------------------------------------------------------------+
//| Manuelles Umschalten auf eine sichere Verbindung                 |
//+------------------------------------------------------------------+
bool TlsHandshake(int socket)
  {
//--- Empfang der Begrüßung des Servers
   string rsp;
 
   if(!RecvString(socket,rsp))
      return(false);
//--- Begrüßung des Servers
   if(!SendString(socket,"EHLO my.domain.com\r\n"))
      return(false);
//--- Erhalt der Serverantwort mit einer Liste der unterstützten Befehle
   if(!RecvString(socket,rsp))
      return(false);
//--- Ausgabe der Begrüßung
   Print("SERVER: ",rsp);
//--- dem Server mitteilen, dass wir von einer unsicheren Verbindung zu einer sicheren Verbindung mit TLS wechseln wollen
   if(!SendString(socket,"STARTTLS\r\n"))
      return(false);
//--- Empfang der Antwort des Servers
   if(!RecvString(socket,rsp))
      return(false);
//--- im Beispiel wird die Antwort des Servers über die Bereitschaft zum Umschalten auf TLS ('Ready to start TLS') nicht überprüft
 
//--- eine sichere Verbindung mit TLS (SSL) zum angegebenen Host unter Verwendung des TLS Handshake-Protokolls einleiten
   if(SocketTlsHandshake(socket,InpTimeout))
      return(true);
 
   Print("SocketTlsHandshake() failed. Error ",GetLastError());
   return(false);
  }
//+------------------------------------------------------------------+
//| Skript Programm Start Funktion                                   |
//+------------------------------------------------------------------+
void OnStart(void)
  {
//--- Socket erstellen und sein Handle zuweisen
   int socket=SocketCreate();
 
   if(socket==INVALID_HANDLE)
     {
      Print("SocketCreate() failed. Error ",GetLastError());
      return;
     }
//--- Verbindung zu SERVER über PORT
   if(!SocketConnect(socket,SERVER,PORT,10000))
     {
      Print("SocketConnect() failed. Error ",GetLastError());
     }
   else
     {
      //--- unsichere Verbindung hergestellt
      PrintFormat("%s connection has been established to %s:%d",(PORT==443 ? "A secured" : "An unsecured"),SERVER,PORT);
      //--- Wechsel zu einer sicheren Verbindung
      if(PORT!=443 && TlsHandshake(socket))
        {
         PrintFormat("Unsecured connection to %s:%d switched to secured",SERVER,PORT);
         //--- wenn die Verbindung durch ein Zertifikat geschützt ist, zeige dessen Daten an
         string   subject,issuer,serial,thumbprint;
         datetime expiration;
 
         if(SocketTlsCertificate(socket,subject,issuer,serial,thumbprint,expiration))
           {
            Print("TLS Zertifikat:");
            Print("   Owner:      ",subject);
            Print("   Issuer:     ",issuer);
            Print("   Number:     ",serial);
            Print("   Print:      ",thumbprint);
            Print("   Expiration: ",expiration);
           }
        }
     }
//--- Schließen des Sockets nach Gebrauch
   SocketClose(socket);
   /*
  Ergebnis:
   An unsecured connection has been established to smtp.gmail.com:587
   SERVER220 smtp.gmail.com ESMTP a640c23a62f3a-a9b1f298319sm82305866b.105 - gsmtp
 
   SERVER250-smtp.gmail.com at your service, [37.193.40.122]
   250-SIZE 35882577
   250-8BITMIME
   250-STARTTLS
   250-ENHANCEDSTATUSCODES
   250-PIPELINING
   250-CHUNKING
   250 SMTPUTF8
 
   SERVER220 2.0.0 Ready to start TLS
 
   SocketTlsHandshake(): A secure connection to smtp.gmail.com:587 is now established
   TLS certificate:
      Owner:  /CN=smtp.gmail.com
      Issuer:  /C=US/O=Google Trust Services/CN=WR2
      Number:     1f:f4:db:2a:5a:e6:dc:52:0a:4c:05:ce:81:cc:c3:f7
      Printd6be8af229b5329cd3d4c2789c02aa94f89b421c
      Expiration2024.12.30 08:25:30
   */
  }
//+------------------------------------------------------------------+
//| Senden einer Zeichenkette an den Server                          |
//+------------------------------------------------------------------+
bool SendString(int socket,const string str)
  {
//--- die Zeichenkette in ein Zeichenarray umwandeln
   uchar data[];
   int   size=StringToCharArray(str,data,0,str.Length(),CP_UTF8);
//--- Senden der Daten an den Socket
   ResetLastError();
   if(SocketSend(socket,data,size)==size)
      return(true);
//--- Fehler während des Sendens der Daten
   Print("Failed to send data to server. Error ",GetLastError());
   return false;
  }
//+------------------------------------------------------------------+
//| Abrufen einer Zeichenkette vom Server                            |
//+------------------------------------------------------------------+
bool RecvString(int socket,stringresult,uint timeout_ms=1000)
  {
//--- warten, bis Daten auf dem Socket erscheinen
   ulong wait_time_end=GetMicrosecondCount()+timeout_ms*1000;
 
   while(!SocketIsReadable(socket))
     {
      Sleep(10);
      //--- Zeitüberschreitung beim Warten auf Daten - als Antwort wird dann NULL zurückgeben
      if(wait_time_end<GetMicrosecondCount())
        {
         Print("ERROR: No response from server");
         return(false);
        }
     }
//--- Lesen der Daten vom Socket
   uchar  data[128];
   uint   size=0;
   string resp=NULL;
 
   do
     {
      uchar b[1];
      int   n=SocketRead(socket,b,1,1000);
 
      if(n < 0)
         break;
 
      if(n)
        {
         data[size++]=b[0];
 
         if(size==data.Size())
           {
            resp += CharArrayToString(data,0,data.Size(),CP_UTF8);
            size = 0;
           }
        }
     }
   while(SocketIsReadable(socket));
//--- Kopieren der gelesenen Daten in die Zeichenkette
   if(size)
      resp+=CharArrayToString(data,0,size,CP_UTF8);
//--- ist die Zeichenkette leer, dann Fehler ausgeben
   if(!resp.Length())
     {
      Print("ERROR: No response from server");
      return(false);
     }
//--- Rückgabe der Zeichenkette
   result=resp;
   return(true);
  }