Quantcast
Channel: AUTOMALABS
Viewing all articles
Browse latest Browse all 63

ESP8266: Como enviar e-mail por uma conexão criptografada (SSL/TLS).

$
0
0

Em um post anterior eu mostrei como se enviava e-mail e adverti para o fato de que a conexão não era segura e as credenciais podiam ser interceptadas (além do fato óbvio do e-mail poder ser lido). Eu achei que enviar por uma conexão segura fosse muito complicado, mas descobri que não é. O problema é que usa muita RAM. O email sem criptografia te deixa com 46KB livres para o resto do seu programa enquanto este aqui te deixa com “apenas” 18KB. Lembre-se de que isso ainda é 9x a RAM total de um Arduino UNO.

Sobre fingerprints e validação de certificado

Se você usa um servidor de e-mail numa conta compartilhada, como é o caso da hostgator, o certificado não vai validar se você colocar o nome do seu domínio como servidor. Você tem que obter o nome correto do servidor de e-mail que atende a sua conta. Na hostgator isso pode ser visto no cPanel.

Por exemplo, meu servidor de e-mail normal seria: meudominio.com.br ou mail.meudominio.com.br mas para validar o certificado eu preciso colocar gator1234.hostgator.com.

O exemplo abaixo é uma adaptação simples do exemplo que não usa criptografia.

/*
 *  Envio de e-mail por SMTP usando conexão criptografada
 *  Jefferson Ryan - automalabs.com.br - Julho de 2017
 *  Testado em um ESP8266 - ESP-01 - IDE Arduino 1.8.1 e ESP8266 Core v2.3.0
 *  Mais informações em http://www.automalabs.com.br/?p=1595
 *  
 */
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

//======== Você precisa preencher estes dados ===========================================
const char* SSID = "";
const char* PASS = "";

char smtp_server[] = "";
const int smtp_port = 465; //465 é a porta segura no meu servidor. A sua pode ser outra.
const String mail_username="nome_do_usuario";
const String mail_password="senha";
const String mail_from="ESP8266 <usuario@servidor_remetente>";
const String mail_to="Jefferson <usuario@servidor_destino>";
const String mail_subject="Enviado pelo ESP8266";
const String mail_line1="Esta é a linha 1\n";
const String mail_line2="Esta é a linha 2";
const String mail_line3="Esta é a linha 3";

//Obtenha com a ajuda de https://www.grc.com/fingerprints.htm
//Precisará ser atualizado manualmente quando o certificado expirar
const char* fingerprint = "";
//=========================================================================================

bool construindoLinha=false;
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// Cria uma conexao SSL/TLS
WiFiClientSecure client;

void printFreeRAM(){
  Serial.print("RAM livre: ");
  Serial.print(ESP.getFreeHeap());
  Serial.println(" bytes.");
}

void a3_to_a4(unsigned char * a4, unsigned char * a3) {
  a4[0] = (a3[0] & 0xfc) >> 2;
  a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
  a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
  a4[3] = (a3[2] & 0x3f);
}

int base64_encode(char *output, const char *input, int inputLen) {
  int i = 0, j = 0;
  int encLen = 0;
  unsigned char a3[3];
  unsigned char a4[4];
  while(inputLen--) {
    a3[i++] = *(input++);
    if(i == 3) {
      a3_to_a4(a4, a3);
      for(i = 0; i < 4; i++) {
        output[encLen++] = _b64_alphabet[a4[i]];
      }
      i = 0;
    }
  }
  if(i) {
    for(j = i; j < 3; j++) {
      a3[j] = '\0';
    }
    a3_to_a4(a4, a3);
    for(j = 0; j < i + 1; j++) {
      output[encLen++] = _b64_alphabet[a4[j]];
    }
    while((i++ < 3)) {
      output[encLen++] = '=';
    }
  }
  output[encLen] = '\0';
  return encLen;
}

void setup()
{
  Serial.begin(115200);
 // Serial.setDebugOutput(true);
  delay(10);
  Serial.println("");
  Serial.println("");
  Serial.print("Conectando a: ");
  Serial.println(SSID);
  Serial.print("Com a senha: ");
  Serial.println(PASS);
  WiFi.begin(SSID, PASS);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Conectado.");
  Serial.print("Endereco IP local: ");
  Serial.println(WiFi.localIP());
  printFreeRAM();
  byte ret = sendEmail();
  printFreeRAM();
}

void loop()
{
}

void SEND(String message)
{
if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
Serial.print (message);
client.print (message);
construindoLinha=true;
  
}

void SENDln(String message)
{
if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
Serial.println (message);
client.println (message);
construindoLinha=false;  
}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  Serial.print("Conectando a: ");
  Serial.println(smtp_server);
  if (!client.connect(smtp_server, smtp_port)) {
    Serial.println("Falha na conexao.");
    return 0;
  }else
  {
    Serial.println("Conectado.");
  }

  if (client.verify(fingerprint,smtp_server)) {
    Serial.println("O certificado confere.");
  } else {
    Serial.println("O certificado nao confere.");
    //return 0; //Descomente esta linha para impedir o envio se o certificado estiver errado
  }


  if (!eRcv()) return 0;

  char* buf = (char*)malloc(100);

  SEND("EHLO ");
  SENDln(smtp_server); 
  if (!eRcv()) return 0;

  SENDln("auth login");
  if (!eRcv()) return 0;

  base64_encode(buf, mail_username.c_str(), mail_username.length());
  client.println(buf);  
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  base64_encode(buf, mail_password.c_str(), mail_password.length());
  client.println(buf);   
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  SEND("MAIL From: ");
  SENDln(mail_from);
  if (!eRcv()) return 0;
  
  SEND("RCPT To: ");
  SENDln(mail_to);
  if (!eRcv()) return 0;
  
  SENDln("DATA");
  if (!eRcv()) return 0;
  
  SEND("To: ");
  SENDln(mail_to);
  SEND("From: "); 
  SENDln(mail_from); //Este é o "nome para exibição"
  SEND("Subject: ");
  SENDln(mail_subject);
  SENDln(mail_line1);
  SENDln(mail_line2);
  SENDln(mail_line3);
  SENDln("."); //O email tem que terminar assim
  if (!eRcv()) return 0;

  SENDln("QUIT");
 
  if (!eRcv()) return 0;
  client.stop();
  Serial.println("Desconectado.");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;
    // Se nada for recebido em 10s, desiste.
    if (loopCount > 10000) {
      client.stop();
      Serial.println("\r\nTimeout");
      return 0;
    }
  }

  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  if (respCode >= '4')
  {
    //  efail();
    return 0;
  }
  return 1;
}

Por alto, as diferenças são 4:

1)Acrescente: #include <WiFiClientSecure.h>

2)Acrescente: const char* fingerprint = “fingerprint_aqui”;

3)Mude: WiFiClient client; para WiFiClientSecure client; 

4)Acrescente a validação de certificado logo após a conexão:

if (client.verify(fingerprint,smtp_server)) {
    Serial.println("O certificado confere.");
  } else {
    Serial.println("O certificado nao confere.");
    //return 0; //Descomente esta linha para impedir o envio se o certificado estiver errado
  }

 


Viewing all articles
Browse latest Browse all 63