SocketTlsHandshake

Initie une connexion TLS (SSL) vers un hôte spécifié via le protocole TLS Handshake. Pendant ce handshake, un client et un serveur se mettent d'accord sur les paramètres de connexion : version du protocole appliqué et méthode d'encryptage des données.

bool  SocketTlsHandshake(
   int           socket,               // socket
   const string  host                  // adresse de l'hôte
   );

Paramètres

socket

[in]  Handle de la socket retournée par la fonction SocketCreate. Lorsqu'un handle incorrect est passé, l'erreur 5270 (ERR_NETSOCKET_INVALIDHANDLE) est écrite dans _LastError.

host

[in]  Adresse d'un hôte avec lequel la conexion sécurisée est établie.

Valeur de Retour

Retourne true en cas de succès, sinon false.

Notes

Avant une connexion sécurisée, le programme doit établir une connexion TCP standard avec l'hôte en utilisant SocketConnect.

Si la connexion sécurisée échoue, l'erreur 5274 (ERR_NETSOCKET_HANDSHAKE_FAILED) est écrite dans _LastError.

Il n'y a pas besoin d'appeler la fonction lors d'une connexion au port 443. C'est un port TCP standard utilisé pour les connexions sécurisées TLS (SSL).

La fonction ne peut être appelée que depuis les Expert Advisors et les scripts, puisqu'ils sont exécutés dans leurs propres threads d'exécution. Si elle est appelée depuis un indicateur, GetLastError() retourne l'erreur 4014 — "Function is not allowed for call".

Exemple :

//+------------------------------------------------------------------+
//|                                           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
//+------------------------------------------------------------------+
//| Bascule manuellement vers une connexion sécurisée                |
//+------------------------------------------------------------------+
bool TlsHandshake(int socket)
  {
//--- obtient le message d'accueil du serveur
   string rsp;
 
   if(!RecvString(socket,rsp))
      return(false);
//--- salue le serveur
   if(!SendString(socket,"EHLO my.domain.com\r\n"))
      return(false);
//--- obtient une réponse du serveur avec une liste des commandes prises en charge
   if(!RecvString(socket,rsp))
      return(false);
//--- affiche le message d'accueil
   Print("SERVER: ",rsp);
//--- informe le serveur que nous souhaitons passer d'une connexion non sécurisée à une connexion sécurisée via TLS
   if(!SendString(socket,"STARTTLS\r\n"))
      return(false);
//--- obtient la réponse du serveur
   if(!RecvString(socket,rsp))
      return(false);
//--- dans l'exemple, nous ne vérifions pas la réponse du serveur concernant la disponibilité à passer à TLS ('Ready to start TLS')
 
//--- initie une connexion TLS (SSL) sécurisée à l'hôte spécifié à l'aide du protocole TLS Handshake
   if(SocketTlsHandshake(socket,InpTimeout))
      return(true);
 
   Print("SocketTlsHandshake() failed. Error ",GetLastError());
   return(false);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart(void)
  {
//--- crée une socket et récupère son handle
   int socket=SocketCreate();
 
   if(socket==INVALID_HANDLE)
     {
      Print("SocketCreate() failed. Error ",GetLastError());
      return;
     }
//--- se connecte à SERVER via le port PORT
   if(!SocketConnect(socket,SERVER,PORT,10000))
     {
      Print("SocketConnect() failed. Error ",GetLastError());
     }
   else
     {
      //--- connexion non sécurisée établie
      PrintFormat("%s connection has been established to %s:%d",(PORT==443 ? "A secured" : "An unsecured"),SERVER,PORT);
      //--- passe en connexion sécurisée
      if(PORT!=443 && TlsHandshake(socket))
        {
         PrintFormat("Unsecured connection to %s:%d switched to secured",SERVER,PORT);
         //--- si la connexion est protégée par un certificat, affiche ses données
         string   subject,issuer,serial,thumbprint;
         datetime expiration;
 
         if(SocketTlsCertificate(socket,subject,issuer,serial,thumbprint,expiration))
           {
            Print("TLS certificate:");
            Print("   Owner:      ",subject);
            Print("   Issuer:     ",issuer);
            Print("   Number:     ",serial);
            Print("   Print:      ",thumbprint);
            Print("   Expiration: ",expiration);
           }
        }
     }
//--- ferme la socket après son utilisation
   SocketClose(socket);
   /*
   résultat :
   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
   */
  }
//+------------------------------------------------------------------+
//| Envoie la chaîne de caractères au serveur                        |
//+------------------------------------------------------------------+
bool SendString(int socket,const string str)
  {
//--- convertit la chaîne en un tableau de caractères
   uchar data[];
   int   size=StringToCharArray(str,data,0,str.Length(),CP_UTF8);
//--- envoie les données à la socket
   ResetLastError();
   if(SocketSend(socket,data,size)==size)
      return(true);
//--- erreur d'envoi de données
   Print("Failed to send data to server. Error ",GetLastError());
   return false;
  }
//+------------------------------------------------------------------+
//| Obtient une chaîne de caractères du serveur                      |
//+------------------------------------------------------------------+
bool RecvString(int socket,stringresult,uint timeout_ms=1000)
  {
//--- attend que les données apparaissent sur la socket
   ulong wait_time_end=GetMicrosecondCount()+timeout_ms*1000;
 
   while(!SocketIsReadable(socket))
     {
      Sleep(10);
      //--- le délai d'attente des données a expiré - renvoie NULL en réponse
      if(wait_time_end<GetMicrosecondCount())
        {
         Print("ERROR: No response from server");
         return(false);
        }
     }
//--- lit les données de la 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));
//--- copie les données lues dans la chaîne
   if(size)
      resp+=CharArrayToString(data,0,size,CP_UTF8);
//--- si la chaîne est vide, alors erreur
   if(!resp.Length())
     {
      Print("ERROR: No response from server");
      return(false);
     }
//--- retourne la chaîne de caractères
   result=resp;
   return(true);
  }