add email client

This commit is contained in:
gemu2015 2020-05-02 08:25:52 +02:00
parent 76c7966069
commit d36f395af4
23 changed files with 13255 additions and 0 deletions

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 mobizt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,278 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
/*
===========================================================================================================================
To prevent stack overrun in case of you want to download email attachments in IMAP readMail,
increase the stack size in app_main() in esp32 main.cpp will help by change the stack size from 8192 to any more value
as following
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
to
xTaskCreatePinnedToCore(loopTask, "loopTask", 16384, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
For Arduino, file esp32's main.cpp is at C:\Users\USER_NAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\main.cpp
And for platformIO, that file is at C:\Users\USER_NAME\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp
===========================================================================================================================
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#include "SD.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Reading data object contains config and data that received
IMAPData imapData;
//Callback function to get the Email reading status
void readCallback(ReadStatus info);
//List all files in SD card
void printDirectory(File &dir, int depth);
void readEmail();
unsigned long lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
MailClient.sdBegin();
//MailClient.sdBegin(14,2,15,13); //SCK, MISO, MOSI,SS for TTGO T8 v1.7 or 1.8
File dir = SD.open("/");
printDirectory(dir, 0);
Serial.println();
imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
imapData.setFolder("INBOX");
//Clear fetch UID
//If fetch UID was set, no search is perform.
imapData.setFetchUID("");
//imapData.setSearchCriteria("UID SINCE 10-Feb-2019");
//imapData.setSearchCriteria("UID 700:*");
//imapData.setSearchCriteria("UID SEARCH NOT SEEN");
//imapData.setSearchCriteria("UID SEARCH UNSEEN");
imapData.setSearchCriteria("UID SEARCH ALL");
//To fetch or read one message UID = 320
//imapData.setFechUID("320");
//Set SD folder to save download messages and attachments
imapData.setSaveFilePath("/email_data");
//Save attachament
imapData.setDownloadAttachment(true);
//Set fetch/search result to return html message
imapData.setHTMLMessage(true);
//Set fetch/search result to return text message
imapData.setTextMessage(true);
//Set to save html message in SD card with decoded content.
imapData.saveHTMLMessage(true, true);
//Set to save text message in SD card with decoded content.
imapData.saveTextMessage(true, true);
//Set the maximum result when search criteria was set.
imapData.setSearchLimit(10);
//Set the sort order of returning message upon most recent received email.
imapData.setRecentSort(true);
//Set the return tex/html message size in byte.
imapData.setMessageBufferSize(200);
//Set the maximum attachment size 5 MB (each file)
imapData.setAttachmentSizeLimit(1024 * 1024 * 5);
//Set the Email receive callback function.
imapData.setReadCallback(readCallback);
//Set to get attachment downloading progress status.
imapData.setDownloadReport(true);
//Set the storage types to save download attachments or messages (SD is default)
//imapData.setFileStorageType(MailClientStorageType::SPIFFS)
imapData.setFileStorageType(MailClientStorageType::SD);
MailClient.readMail(imapData);
}
void readEmail()
{
Serial.println();
Serial.println("Read Email...");
imapData.setFetchUID("10");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
imapData.setFetchUID("11");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
imapData.setFetchUID("12");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
}
void loop()
{
if (millis() - lastTime > 1000 * 60 * 3)
{
lastTime = millis();
Serial.println(ESP.getFreeHeap());
readEmail();
}
}
//Callback function to get the Email reading status
void readCallback(ReadStatus msg)
{
//Print the current status
Serial.println("INFO: " + msg.info());
if (msg.status() != "")
Serial.println("STATUS: " + msg.status());
//Show the result when reading finished
if (msg.success())
{
for (int i = 0; i < imapData.availableMessages(); i++)
{
Serial.println("=================");
//Search result number which varied upon search crieria
Serial.println("Messsage Number: " + imapData.getNumber(i));
//UID only available when assigned UID keyword in setSearchCriteria
//e.g. imapData.setSearchCriteria("UID SEARCH ALL");
Serial.println("Messsage UID: " + imapData.getUID(i));
Serial.println("Messsage ID: " + imapData.getMessageID(i));
Serial.println("Accept Language: " + imapData.getAcceptLanguage(i));
Serial.println("Content Language: " + imapData.getContentLanguage(i));
Serial.println("From: " + imapData.getFrom(i));
Serial.println("From Charset: " + imapData.getFromCharset(i));
Serial.println("To: " + imapData.getTo(i));
Serial.println("To Charset: " + imapData.getToCharset(i));
Serial.println("CC: " + imapData.getCC(i));
Serial.println("CC Charset: " + imapData.getCCCharset(i));
Serial.println("Date: " + imapData.getDate(i));
Serial.println("Subject: " + imapData.getSubject(i));
Serial.println("Subject Charset: " + imapData.getSubjectCharset(i));
//If setHeaderOnly to false;
if (!imapData.isHeaderOnly())
{
Serial.println("Text Message: " + imapData.getTextMessage(i));
Serial.println("Text Message Charset: " + imapData.getTextMessgaeCharset(i));
Serial.println("HTML Message: " + imapData.getHTMLMessage(i));
Serial.println("HTML Message Charset: " + imapData.getHTMLMessgaeCharset(i));
if (imapData.isFetchMessageFailed(i))
Serial.println("Fetch Error: " + imapData.getFetchMessageFailedReason(i));
if (imapData.isDownloadMessageFailed(i))
Serial.println("Save Content Error: " + imapData.getDownloadMessageFailedReason(i));
if (imapData.getAttachmentCount(i) > 0)
{
Serial.println("**************");
Serial.println("Attachment: " + String(imapData.getAttachmentCount(i)) + " file(s)");
for (int j = 0; j < imapData.getAttachmentCount(i); j++)
{
Serial.println("File Index: " + String(j + 1));
Serial.println("Filename: " + imapData.getAttachmentFileName(i, j));
Serial.println("Name: " + imapData.getAttachmentName(i, j));
Serial.println("Size: " + String(imapData.getAttachmentFileSize(i, j)));
Serial.println("Type: " + imapData.getAttachmentType(i, j));
Serial.println("Creation Date: " + imapData.getAttachmentCreationDate(i, j));
if (imapData.isDownloadAttachmentFailed(i, j))
Serial.println("Download Attachment Error: " + imapData.getDownloadAttachmentFailedReason(i, j));
}
}
}
Serial.println();
}
}
}
//List all files in SD card
void printDirectory(File &dir, int depth)
{
while (true)
{
File entry = dir.openNextFile();
if (!entry)
break;
for (uint8_t i = 0; i < depth; i++)
Serial.print("| ");
std::string name = entry.name();
if (entry.isDirectory())
{
Serial.print("+----" + String(name.substr(name.find_last_of("/\\") + 1).c_str()) + "\r\n");
printDirectory(entry, depth + 1);
}
else
{
Serial.print("+--" + String(name.substr(name.find_last_of("/\\") + 1).c_str()));
Serial.print("\t\t\t(");
Serial.print(entry.size(), DEC);
Serial.println(")");
}
entry.close();
}
}

View File

@ -0,0 +1,180 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
#include <Arduino.h>
#include "ESP32_MailClient.h"
#include "SD.h"
//For demo only
#include "image.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Sending data object contains config and data to send
SMTPData smtpData;
//Callback function to get the Email sending status
void sendCallback(SendStatus info);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.println("Mounting SD Card...");
if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8
{
Serial.println("Preparing attach file...");
File file = SD.open("/text_file.txt", FILE_WRITE);
file.print("Hello World!\r\nHello World!");
file.close();
file = SD.open("/binary_file.dat", FILE_WRITE);
static uint8_t buf[512];
buf[0] = 'H';
buf[1] = 'E';
buf[2] = 'A';
buf[3] = 'D';
file.write(buf, 4);
size_t i;
memset(buf, 0xff, 512);
for (i = 0; i < 2048; i++)
{
file.write(buf, 512);
}
buf[0] = 'T';
buf[1] = 'A';
buf[2] = 'I';
buf[3] = 'L';
file.write(buf, 4);
file.close();
}
else
{
Serial.println("SD Card Monting Failed");
}
Serial.println();
Serial.println("Sending email...");
//Set the Email host, port, account and password
smtpData.setLogin("outlook.office365.com", 587, "YOUR_EMAIL_ACCOUNT@outlook.com", "YOUR_EMAIL_PASSWORD");
//For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
//enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
//smtpData.setSTARTTLS(true);
//Set the sender name and Email
smtpData.setSender("ESP32", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com");
//Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
smtpData.setPriority("High");
//Set the subject
smtpData.setSubject("ESP32 SMTP Mail Sending Test");
//Set the message - normal text or html format
smtpData.setMessage("<div style=\"color:#ff0000;font-size:20px;\">Hello World! - From ESP32</div>", true);
//Add recipients, can add more than one recipient
smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com");
//Add attachments, can add the file or binary data from flash memory, file in SD card
//Data from internal memory
smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData);
//Add attach files from SD card
//Comment these two lines, if no SD card connected
//Two files that previousely created.
smtpData.addAttachFile("/binary_file.dat");
smtpData.addAttachFile("/text_file.txt");
//Add some custom header to message
//See https://tools.ietf.org/html/rfc822
//These header fields can be read from raw or source of message when it received)
smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
//Be careful when set Message-ID, it should be unique, otherwise message will not store
//smtpData.addCustomMessageHeader("Message-ID: <abcde.fghij@gmail.com>");
//Set the storage types to read the attach files (SD is default)
//smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
smtpData.setFileStorageType(MailClientStorageType::SD);
smtpData.setSendCallback(sendCallback);
//Start sending Email, can be set callback function to track the status
if (!MailClient.sendMail(smtpData))
Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
//Clear all data from Email object to free memory
smtpData.empty();
}
void loop()
{
}
//Callback function to get the Email sending status
void sendCallback(SendStatus msg)
{
//Print the current status
Serial.println(msg.info());
//Do something when complete
if (msg.success())
{
Serial.println("----------------");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Reading data object contains config and data that received
IMAPData imapData;
void readEmail();
unsigned long lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.println();
imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
imapData.setFolder("INBOX");
imapData.setDebug(true);
//Set \Seen and \Answered to flags for message with UID 100
MailClient.setFlag(imapData, 100, "\\Seen \\Answered");
//Add \Seen and \Answered to flags for message with UID 100
//MailClient.addFlag(imapData, 100, "\\Seen \\Answered");
//Remove \Seen and \Answered from flags for message with UID 100
//MailClient.removeFlag(imapData, 100, "\\Seen \\Answered");
}
void loop()
{
}

View File

@ -0,0 +1,136 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
//Set Clock
//GMT offset (3 Hrs), Daylight offset (0 Hrs)
MailClient.Time.setClock(3, 0);
Serial.println("Number of Days This Year (since January): " + String(MailClient.Time.getNumberOfDayThisYear()));
Serial.println("Day of Week Number: " + String(MailClient.Time.getDayOfWeek()));
Serial.println("Day of Week String: : " + String(MailClient.Time.getDayOfWeekString()));
Serial.println("Total seconds today: : " + String(MailClient.Time.getCurrentSecond()));
Serial.println();
}
void loop()
{
if (!MailClient.Time.clockReady)
return;
//Print out current date and time
int d = MailClient.Time.getDay();
int m = MailClient.Time.getMonth();
int y = MailClient.Time.getYear();
int hr = MailClient.Time.getHour();
int min = MailClient.Time.getMin();
int sec = MailClient.Time.getSec();
Serial.print("Current Time (GMT+3): ");
Serial.print(d);
Serial.print("/");
Serial.print(m);
Serial.print("/");
Serial.print(y);
Serial.print(" ");
Serial.print(hr);
Serial.print(":");
Serial.print(min);
Serial.print(":");
Serial.println(sec);
uint32_t todayFromMidnightTimestamp = MailClient.Time.getTimestamp(y, m, d, 0, 0, 0);
uint32_t currentTimestamp = MailClient.Time.getUnixTime();
uint32_t totalSecondsFromMidnight = currentTimestamp - todayFromMidnightTimestamp;
//Assumed we countdown until 15:00:00 everyday
uint8_t targetSec = 0;
uint8_t targetMin = 0;
uint8_t targetHr = 15;
uint32_t targetSecondsFromMidnight = targetHr * 60 * 60 + targetMin * 60 + targetSec;
if (targetSecondsFromMidnight >= totalSecondsFromMidnight)
{
uint32_t diffSeconds = targetSecondsFromMidnight - totalSecondsFromMidnight;
int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
Serial.print("Everyday countdown until 15:00:00 is ");
Serial.print(remainHr);
Serial.print(" Hr, ");
Serial.print(remainMin);
Serial.print(" Min and ");
Serial.print(remainSec);
Serial.println(" Sec to go.");
}
else
{
Serial.println("Everyday countdown until 15:00:00 was passed.");
}
//Assumed we countdown until 18/12/2019 8:30:45
uint32_t targetTimestamp = MailClient.Time.getTimestamp(2019, 12, 18, 8, 30, 45);
if (targetTimestamp >= currentTimestamp)
{
uint32_t diffSeconds = targetTimestamp - currentTimestamp;
int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
Serial.print("One time countdown until 18/12/2019 8:30:45 is ");
Serial.print(remainYrs);
Serial.print(" Years, ");
Serial.print(remainMonths);
Serial.print(" Months, ");
Serial.print(remainDays);
Serial.print(" Days, ");
Serial.print(remainHr);
Serial.print(" Hr, ");
Serial.print(remainMin);
Serial.print(" Min and ");
Serial.print(remainSec);
Serial.println(" Sec to go.");
}
else
{
Serial.println("One time countdown until 18/12/2019 8:30:45 was finished.");
}
Serial.println();
delay(1000);
}

View File

@ -0,0 +1,166 @@
#######################################
# Syntax Coloring Map ESP32-Mail-Client
#######################################
#######################################
# Classes (KEYWORD1)
#######################################
IMAPData KEYWORD1
SMTPData KEYWORD1
attachmentData KEYWORD1
SendStatus KEYWORD1
messageBodyData KEYWORD1
DownloadProgress KEYWORD1
MessageData KEYWORD1
TIME KEYWORD1
##################################
# Methods and Functions (KEYWORD2)
##################################
sendMail KEYWORD2
readMail KEYWORD2
smtpErrorReason KEYWORD2
imapErrorReason KEYWORD2
sdBegin KEYWORD2
setFlag KEYWORD2
addFlag KEYWORD2
removeFlag KEYWORD2
setClock KEYWORD2
getUnixTime KEYWORD2
getTimestamp KEYWORD2
getYear KEYWORD2
getMonth KEYWORD2
getDay KEYWORD2
getDayOfWeek KEYWORD2
getDayOfWeekString KEYWORD2
getHour KEYWORD2
getMin KEYWORD2
getSec KEYWORD2
getNumberOfDayThisYear KEYWORD2
getTotalDays KEYWORD2
dayofweek KEYWORD2
getCurrentSecond KEYWORD2
getCurrentTimestamp KEYWORD2
getTimeFromSec KEYWORD2
#########################################
# Methods for IMAP Data object (KEYWORD2)
#########################################
setLogin KEYWORD2
setSTARTTLS KEYWORD2
setDebug KEYWORD2
setFolder KEYWORD2
setMessageBufferSize KEYWORD2
setAttachmentSizeLimit KEYWORD2
setSearchCriteria KEYWORD2
setSaveFilePath KEYWORD2
setFechUID KEYWORD2
setDownloadAttachment KEYWORD2
setHTMLMessage KEYWORD2
setTextMessage KEYWORD2
setSearchLimit KEYWORD2
setRecentSort KEYWORD2
setReadCallback KEYWORD2
setDownloadReport KEYWORD2
isHeaderOnly KEYWORD2
getFrom KEYWORD2
getFromCharset KEYWORD2
getTo KEYWORD2
getToCharset KEYWORD2
getCC KEYWORD2
getCCCharset KEYWORD2
getSubject KEYWORD2
getSubjectCharset KEYWORD2
getHTMLMessage KEYWORD2
getTextMessage KEYWORD2
getHTMLMessgaeCharset KEYWORD2
getTextMessgaeCharset KEYWORD2
getDate KEYWORD2
getUID KEYWORD2
getNumber KEYWORD2
getMessageID KEYWORD2
getAcceptLanguage KEYWORD2
getContentLanguage KEYWORD2
isFetchMessageFailed KEYWORD2
getFetchMessageFailedReason KEYWORD2
isDownloadAttachmentFailed KEYWORD2
getDownloadAttachmentFailedReason KEYWORD2
isDownloadMessageFailed KEYWORD2
getDownloadMessageFailedReason KEYWORD2
saveHTMLMessage KEYWORD2
saveTextMessage KEYWORD2
getFolderCount KEYWORD2
getFolder KEYWORD2
getFlagCount KEYWORD2
getFlag KEYWORD2
totalMessages KEYWORD2
searchCount KEYWORD2
availableMessages KEYWORD2
getAttachmentCount KEYWORD2
getAttachmentFileName KEYWORD2
getAttachmentName KEYWORD2
getAttachmentFileSize KEYWORD2
getAttachmentCreationDate KEYWORD2
getAttachmentType KEYWORD2
empty KEYWORD2
clearMessageData KEYWORD2
#########################################
# Methods for SMTP Data object (KEYWORD2)
#########################################
setSender KEYWORD2
getFromName KEYWORD2
getSenderEmail KEYWORD2
setPriority KEYWORD2
getPriority KEYWORD2
addRecipient KEYWORD2
removeRecipient KEYWORD2
clearRecipient KEYWORD2
getRecipient KEYWORD2
recipientCount KEYWORD2
setSubject KEYWORD2
getSubject KEYWORD2
setMessage KEYWORD2
getMessage KEYWORD2
htmlFormat KEYWORD2
addCC KEYWORD2
removeCC KEYWORD2
clearCC KEYWORD2
getCC KEYWORD2
ccCount KEYWORD2
addBCC KEYWORD2
removeBCC KEYWORD2
clearBCC KEYWORD2
getBCC KEYWORD2
bccCount KEYWORD2
addAttachData KEYWORD2
removeAttachData KEYWORD2
attachDataCount KEYWORD2
addAttachFile KEYWORD2
removeAttachFile KEYWORD2
clearAttachData KEYWORD2
clearAttachFile KEYWORD2
clearAttachment KEYWORD2
attachFileCount KEYWORD2
setSendCallback KEYWORD2
############################################################
# Functions for ReadStatus and SendStatus classes (KEYWORD2)
############################################################
SendStatus KEYWORD2
info KEYWORD2
success KEYWORD2
ReadStatus KEYWORD2
status KEYWORD2
clockReady KEYWORD3

View File

@ -0,0 +1,17 @@
name=ESP32 Mail Client
version=2.1.4
author=Mobizt
maintainer=Mobizt <k_suwatchai@hotmail.com.com>
sentence=Mail Client Arduino Library for ESP32
paragraph=This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers.
category=Communication
url=https://github.com/mobizt/ESP32-Mail-Client
architectures=esp32

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,200 @@
/*
* Customized version of ESP32 HTTPClient Library.
* Allow custom header and payload with STARTTLS support
*
* v 1.0.0
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP32MailHTTPClient_CPP
#define ESP32MailHTTPClient_CPP
#ifdef ESP32
#include "ESP32MailHTTPClient.h"
class TransportTraits
{
public:
virtual ~TransportTraits() {}
virtual std::unique_ptr<WiFiClient> create()
{
return std::unique_ptr<WiFiClient>(new WiFiClient());
}
virtual bool
verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb)
{
return true;
}
};
class TLSTraits : public TransportTraits
{
public:
TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
std::unique_ptr<WiFiClient> create() override
{
return std::unique_ptr<WiFiClient>(new WiFiClientSecureESP32());
}
bool verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb) override
{
WiFiClientSecureESP32 &wcs = static_cast<WiFiClientSecureESP32 &>(client);
wcs.setCACert(_cacert);
wcs.setCertificate(_clicert);
wcs.setPrivateKey(_clikey);
wcs.setSTARTTLS(starttls);
wcs.setDebugCB(cb);
return true;
}
protected:
const char *_cacert;
const char *_clicert;
const char *_clikey;
};
ESP32MailHTTPClient::ESP32MailHTTPClient() {}
ESP32MailHTTPClient::~ESP32MailHTTPClient()
{
if (_client)
_client->stop();
}
bool ESP32MailHTTPClient::begin(const char *host, uint16_t port, const char *uri, const char *CAcert)
{
transportTraits.reset(nullptr);
_host = host;
_port = port;
_uri = uri;
transportTraits = TransportTraitsPtr(new TLSTraits(CAcert));
return true;
}
bool ESP32MailHTTPClient::connected()
{
if (_client)
return ((_client->available() > 0) || _client->connected());
return false;
}
bool ESP32MailHTTPClient::sendHeader(const char *header)
{
if (!connected())
return false;
return (_client->write(header, strlen(header)) == strlen(header));
}
int ESP32MailHTTPClient::sendRequest(const char *header, const char *payload)
{
size_t size = strlen(payload);
if (strlen(header) > 0)
{
if (!connect())
return HTTPC_ERROR_CONNECTION_REFUSED;
if (!sendHeader(header))
return HTTPC_ERROR_SEND_HEADER_FAILED;
}
if (size > 0)
if (_client->write(&payload[0], size) != size)
return HTTPC_ERROR_SEND_PAYLOAD_FAILED;
return 0;
}
WiFiClient *ESP32MailHTTPClient::getStreamPtr(void)
{
if (connected())
return _client.get();
return nullptr;
}
bool ESP32MailHTTPClient::connect(void)
{
if (connected())
{
while (_client->available() > 0)
_client->read();
return true;
}
if (!transportTraits)
return false;
_client = transportTraits->create();
if (!transportTraits->verify(*_client, _host.c_str(), false, _debugCallback))
{
_client->stop();
return false;
}
if (!_client->connect(_host.c_str(), _port))
return false;
return connected();
}
bool ESP32MailHTTPClient::connect(bool starttls)
{
if (connected())
{
while (_client->available() > 0)
_client->read();
return true;
}
if (!transportTraits)
return false;
_client = transportTraits->create();
if (!transportTraits->verify(*_client, _host.c_str(), starttls, _debugCallback))
{
_client->stop();
return false;
}
if (!_client->connect(_host.c_str(), _port))
return false;
return connected();
}
void ESP32MailHTTPClient::setDebugCallback(DebugMsgCallback cb)
{
_debugCallback = std::move(cb);
}
#endif //ESP32
#endif //ESP32MailHTTPClient_CPP

View File

@ -0,0 +1,107 @@
/*
* Customized version of ESP32 HTTPClient Library.
* Allow custom header and payload with STARTTLS support
*
* v 1.0.0
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP32MailHTTPClient_H
#define ESP32MailHTTPClient_H
#ifdef ESP32
#include <Arduino.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
#include "WiFiClientSecureESP32.h"
class ESP32MailHTTPClient : public HTTPClient
{
public:
ESP32MailHTTPClient();
~ESP32MailHTTPClient();
/**
* Initialization of new http connection.
* \param host - Host name without protocols.
* \param port - Server's port.
* \param uri - The URI of resource.
* \param CAcert - The Base64 encode root certificate string
* \return True as default.
* If no certificate string provided, use (const char*)NULL to CAcert param
*/
bool begin(const char *host, uint16_t port, const char *uri, const char *CAcert);
/**
* Check the http connection status.
* \return True if connected.
*/
bool connected();
/**
* Establish http connection if header provided and send it, send payload if provided.
* \param header - The header string (constant chars array).
* \param payload - The payload string (constant chars array), optional.
* \return http status code, Return zero if new http connection and header and/or payload sent
* with no error or no header and payload provided. If obly payload provided, no new http connection was established.
*/
int sendRequest(const char *header, const char *payload);
/**
* Send extra header without making new http connection (if sendRequest has been called)
* \param header - The header string (constant chars array).
* \return True if header sending success.
* Need to call sendRequest with header first.
*/
bool sendHeader(const char *header);
/**
* Get the WiFi client pointer.
* \return WiFi client pointer.
*/
WiFiClient *getStreamPtr(void);
uint16_t tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool connect(void);
bool connect(bool starttls);
void setDebugCallback(DebugMsgCallback cb);
protected:
TransportTraitsPtr transportTraits;
std::unique_ptr<WiFiClient> _client;
DebugMsgCallback _debugCallback = NULL;
std::string _host = "";
std::string _uri = "";
uint16_t _port = 0;
};
#endif //ESP32
#endif //ESP32MailHTTPClient_H

View File

@ -0,0 +1,191 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef ESP32TimeHelper_CPP
#define ESP32TimeHelper_CPP
#ifdef ESP32
#include "ESP32TimeHelper.h"
ESP32TimeHelper::ESP32TimeHelper()
{
}
uint32_t ESP32TimeHelper::getUnixTime()
{
uint32_t utime = (msec_time_diff + millis()) / 1000;
return utime;
}
time_t ESP32TimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec)
{
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = date;
timeinfo.tm_hour = hour;
timeinfo.tm_min = mins;
timeinfo.tm_sec = sec;
time_t ts = mktime(&timeinfo);
return ts;
}
bool ESP32TimeHelper::setClock(float gmtOffset, float daylightOffset)
{
TZ = gmtOffset;
DST_MN = daylightOffset;
configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov", NULL);
now = time(nullptr);
int cnt = 0;
while (now < 8 * 3600 * 2 && cnt < 20)
{
delay(50);
now = time(nullptr);
cnt++;
}
uint64_t tmp = now;
tmp = tmp * 1000;
msec_time_diff = tmp - millis();
getLocalTime(&timeinfo);
clockReady = now > 8 * 3600 * 2;
return clockReady;
}
int ESP32TimeHelper::getYear()
{
getLocalTime(&timeinfo);
return timeinfo.tm_year + 1900;
}
int ESP32TimeHelper::getMonth()
{
getLocalTime(&timeinfo);
return timeinfo.tm_mon + 1;
}
int ESP32TimeHelper::getDay()
{
getLocalTime(&timeinfo);
return timeinfo.tm_mday;
}
int ESP32TimeHelper::getDayOfWeek()
{
getLocalTime(&timeinfo);
return timeinfo.tm_wday;
}
String ESP32TimeHelper::getDayOfWeekString()
{
getLocalTime(&timeinfo);
return dow[timeinfo.tm_wday];
}
int ESP32TimeHelper::getHour()
{
getLocalTime(&timeinfo);
return timeinfo.tm_hour;
}
int ESP32TimeHelper::getMin()
{
getLocalTime(&timeinfo);
return timeinfo.tm_min;
}
int ESP32TimeHelper::getSec()
{
getLocalTime(&timeinfo);
return timeinfo.tm_sec;
}
int ESP32TimeHelper::getNumberOfDayThisYear()
{
getLocalTime(&timeinfo);
return timeinfo.tm_yday + 1;
}
int ESP32TimeHelper::totalDays(int y, int m, int d)
{
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
int daystotal = d;
for (int year = 1; year <= y; year++)
{
int max_month = (year < y ? 12 : m - 1);
int leap = (year % 4 == 0);
if (year % 100 == 0 && year % 400 != 0)
leap = 0;
for (int month = 1; month <= max_month; month++)
{
daystotal += daytab[leap][month];
}
}
return daystotal;
}
int ESP32TimeHelper::getTotalDays(int year, int month, int day)
{
return totalDays(year, month, day) - totalDays(1970, 1, 1);
}
int ESP32TimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= month < 3;
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
int ESP32TimeHelper::getCurrentSecond()
{
return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec;
}
uint64_t ESP32TimeHelper::getCurrentTimestamp()
{
return now;
}
void ESP32TimeHelper::getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec)
{
int _yrs = secCount / (365 * 24 * 3600);
secCount = secCount - _yrs * (365 * 24 * 3600);
yrs = _yrs;
int _months = secCount / (30* 24 * 3600);
secCount = secCount - _months * (30 * 24 * 3600);
months = _months;
int _days = secCount / (24 * 3600);
secCount = secCount - _days * (24 * 3600);
days = _days;
int _hr = secCount / 3600;
secCount = secCount - _hr * 3600;
hr = _hr;
int _min = secCount / 60;
secCount = secCount - _min * 60;
min = _min;
sec = secCount;
}
#endif //ESP32
#endif //ESP32TimeHelper_CPP

View File

@ -0,0 +1,73 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef ESP32TimeHelper_H
#define ESP32TimeHelper_H
#ifdef ESP32
#include <time.h>
#include <Arduino.h>
#include <WiFi.h>
class ESP32TimeHelper
{
public:
ESP32TimeHelper();
bool clockReady = false;
bool setClock(float gmtOffset, float daylightOffset);
uint32_t getUnixTime();
time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec);
int getYear();
int getMonth();
int getDay();
int getDayOfWeek();
String getDayOfWeekString();
int getHour();
int getMin();
int getSec();
int getNumberOfDayThisYear();
int getTotalDays(int year, int month, int day);
int dayofWeek(int year, int month, int day);
int getCurrentSecond();
uint64_t getCurrentTimestamp();
void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec);
private:
time_t now;
uint64_t msec_time_diff = 0;
struct tm timeinfo;
float TZ = 0.0;
float DST_MN = 0.0;
bool setClock();
int totalDays(int y, int m, int d);
const char *dow[20] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"};
};
#endif //ESP32
#endif //ESP32TimeHelper_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,240 @@
#ifndef RFC2047_CPP
#define RFC2047_CPP
#ifdef ESP32
#include "RFC2047.h"
RFC2047::RFC2047(){}
void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){
const char *p, *q;
size_t n;
int found_encoded = 0;
dlen--; /* save room for the terminal nul */
while (*s && dlen > 0)
{
if ((p = strstr (s, "=?")) == NULL ||
(q = strchr (p + 2, '?')) == NULL ||
(q = strchr (q + 1, '?')) == NULL ||
(q = strstr (q + 1, "?=")) == NULL)
{
/* no encoded words */
if (d != s)
strfcpy (d, s, dlen + 1);
return;
}
if (p != s)
{
n = (size_t) (p - s);
/* ignore spaces between encoded words */
if (!found_encoded || strspn (s, " \t\r\n") != n)
{
if (n > dlen)
n = dlen;
if (d != s)
memcpy (d, s, n);
d += n;
dlen -= n;
}
}
rfc2047DecodeWord (d, p, dlen);
found_encoded = 1;
s = q + 2;
n = strlen (d);
dlen -= n;
d += n;
}
*d = 0;
}
void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){
char *p = safe_strdup (s);
char *pp = p;
char *pd = d;
size_t len = dlen;
int enc = 0, filter = 0, count = 0, c1, c2, c3, c4;
while ((pp = strtok (pp, "?")) != NULL)
{
count++;
switch (count)
{
case 2:
if (strcasecmp (pp, Charset) != 0)
{
filter = 1;
}
break;
case 3:
if (toupper (*pp) == 'Q')
enc = ENCQUOTEDPRINTABLE;
else if (toupper (*pp) == 'B')
enc = ENCBASE64;
else
return;
break;
case 4:
if (enc == ENCQUOTEDPRINTABLE)
{
while (*pp && len > 0)
{
if (*pp == '_')
{
*pd++ = ' ';
len--;
}
else if (*pp == '=')
{
*pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]);
len--;
pp += 2;
}
else
{
*pd++ = *pp;
len--;
}
pp++;
}
*pd = 0;
}
else if (enc == ENCBASE64)
{
while (*pp && len > 0)
{
c1 = base64val(pp[0]);
c2 = base64val(pp[1]);
*pd++ = (c1 << 2) | ((c2 >> 4) & 0x3);
if (--len == 0) break;
if (pp[2] == '=') break;
c3 = base64val(pp[2]);
*pd++ = ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf);
if (--len == 0)
break;
if (pp[3] == '=')
break;
c4 = base64val(pp[3]);
*pd++ = ((c3 & 0x3) << 6) | c4;
if (--len == 0)
break;
pp += 4;
}
*pd = 0;
}
break;
}
pp = 0;
}
safe_free (&p);
if (filter)
{
pd = d;
while (*pd)
{
if (!IsPrint (*pd))
*pd = '?';
pd++;
}
}
return;
}
void *RFC2047::safe_calloc (size_t nmemb, size_t size)
{
void *p;
if (!nmemb || !size)
return NULL;
if (!(p = calloc (nmemb, size)))
{
//out of memory
return NULL;
}
return p;
}
void *RFC2047::safe_malloc (unsigned int siz)
{
void *p;
if (siz == 0)
return 0;
if ((p = (void *) malloc (siz)) == 0)
{
//out of memory
return NULL;
}
return (p);
}
void RFC2047::safe_realloc (void **p, size_t siz)
{
void *r;
if (siz == 0)
{
if (*p)
{
free (*p);
*p = NULL;
}
return;
}
if (*p)
r = (void *) realloc (*p, siz);
else
{
r = (void *) malloc (siz);
}
if (!r)
{
//out of memory
return;
}
*p = r;
}
void RFC2047::safe_free (void *ptr)
{
void **p = (void **)ptr;
if (*p)
{
free (*p);
*p = 0;
}
}
char *RFC2047::safe_strdup (const char *s)
{
char *p;
size_t l;
if (!s || !*s) return 0;
l = strlen (s) + 1;
p = (char *)safe_malloc (l);
memcpy (p, s, l);
return (p);
}
#endif //ESP32
#endif //RFC2047_CPP

View File

@ -0,0 +1,70 @@
#ifndef RFC2047_H
#define RFC2047_H
#ifdef ESP32
#include <Arduino.h>
#define strfcpy(A,B,C) strncpy(A,B,C), *(A+(C)-1)=0
enum
{
ENCOTHER,
ENC7BIT,
ENC8BIT,
ENCQUOTEDPRINTABLE,
ENCBASE64,
ENCBINARY
};
__attribute__((used)) static const char *Charset = "utf-8";
__attribute__((used)) static int Index_hex[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
__attribute__((used)) static int Index_64[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1};
#define IsPrint(c) (isprint((unsigned char)(c)) || \
((unsigned char)(c) >= 0xa0))
#define hexval(c) Index_hex[(unsigned int)(c)]
#define base64val(c) Index_64[(unsigned int)(c)]
class RFC2047{
public:
RFC2047();
void rfc2047Decode(char *d, const char *s, size_t dlen);
private:
void rfc2047DecodeWord(char *d, const char *s, size_t dlen);
void *safe_calloc (size_t nmemb, size_t size);
void *safe_malloc (unsigned int siz);
void safe_realloc (void **p, size_t siz);
void safe_free (void *ptr);
char *safe_strdup (const char *s);
};
#endif //ESP32
#endif //RFC2047_H

View File

@ -0,0 +1,397 @@
/*
*Customized WiFiClientSecure.cpp to support STARTTLS protocol, version 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
WiFiClientSecureESP32.cpp - Client Secure class for ESP32
Copyright (c) 2016 Hristo Gochkov All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WiFiClientSecureESP32_CPP
#define WiFiClientSecureESP32_CPP
#ifdef ESP32
#include "WiFiClientSecureESP32.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
#undef connect
#undef write
#undef read
WiFiClientSecureESP32::WiFiClientSecureESP32()
{
_connected = false;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::WiFiClientSecureESP32(int sock)
{
_connected = false;
_timeout = 0;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = sock;
sslclient->handshake_timeout = 120000;
if (sock >= 0) {
_connected = true;
}
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::WiFiClientSecureESP32(bool starttls)
{
_connected = false;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
sslclient->starttls = true;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::~WiFiClientSecureESP32()
{
stop();
delete sslclient;
}
WiFiClientSecureESP32 &WiFiClientSecureESP32::operator=(const WiFiClientSecureESP32 &other)
{
stop();
sslclient->socket = other.sslclient->socket;
_connected = other._connected;
return *this;
}
void WiFiClientSecureESP32::stop()
{
if (sslclient->socket >= 0) {
close(sslclient->socket);
sslclient->socket = -1;
_connected = false;
_peek = -1;
}
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(ip, port, _pskIdent, _psKey);
return connect(ip, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, int32_t timeout){
_timeout = timeout;
return connect(ip, port);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(host, port, _pskIdent, _psKey);
return connect(host, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, int32_t timeout){
_timeout = timeout;
return connect(host, port);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
_connected = true;
return 1;
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) {
return connect(ip.toString().c_str(), port,_pskIdent, _psKey);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) {
log_v("start_ssl_client with PSK");
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
_connected = true;
return 1;
}
int WiFiClientSecureESP32::peek(){
if(_peek >= 0){
return _peek;
}
_peek = timedRead();
return _peek;
}
size_t WiFiClientSecureESP32::write(uint8_t data)
{
return write(&data, 1);
}
int WiFiClientSecureESP32::read()
{
uint8_t data = -1;
int res = read(&data, 1);
if (res < 0) {
return res;
}
return data;
}
size_t WiFiClientSecureESP32::write(const uint8_t *buf, size_t size)
{
if (!_connected) {
return 0;
}
int res = send_ssl_data(sslclient, buf, size);
if (res < 0) {
stop();
res = 0;
}
return res;
}
int WiFiClientSecureESP32::read(uint8_t *buf, size_t size)
{
int peeked = 0;
int avail = available();
if ((!buf && size) || avail <= 0) {
return -1;
}
if(!size){
return 0;
}
if(_peek >= 0){
buf[0] = _peek;
_peek = -1;
size--;
avail--;
if(!size || !avail){
return 1;
}
buf++;
peeked = 1;
}
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0) {
stop();
return peeked?peeked:res;
}
return res + peeked;
}
int WiFiClientSecureESP32::available()
{
int peeked = (_peek >= 0);
if (!_connected) {
return peeked;
}
int res = data_to_read(sslclient);
if (res < 0) {
stop();
return peeked?peeked:res;
}
return res+peeked;
}
uint8_t WiFiClientSecureESP32::connected()
{
uint8_t dummy = 0;
read(&dummy, 0);
return _connected;
}
void WiFiClientSecureESP32::setCACert (const char *rootCA)
{
_CA_cert = rootCA;
}
void WiFiClientSecureESP32::setCertificate (const char *client_ca)
{
_cert = client_ca;
}
void WiFiClientSecureESP32::setPrivateKey (const char *private_key)
{
_private_key = private_key;
}
void WiFiClientSecureESP32::setPreSharedKey(const char *pskIdent, const char *psKey) {
_pskIdent = pskIdent;
_psKey = psKey;
}
bool WiFiClientSecureESP32::verify(const char* fp, const char* domain_name)
{
if (!sslclient)
return false;
return verify_ssl_fingerprint(sslclient, fp, domain_name);
}
char *WiFiClientSecureESP32::_streamLoad(Stream& stream, size_t size) {
static char *dest = nullptr;
if(dest) {
free(dest);
}
dest = (char*)malloc(size);
if (!dest) {
return nullptr;
}
if (size != stream.readBytes(dest, size)) {
free(dest);
dest = nullptr;
}
return dest;
}
bool WiFiClientSecureESP32::loadCACert(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setCACert(dest);
ret = true;
}
return ret;
}
bool WiFiClientSecureESP32::loadCertificate(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setCertificate(dest);
ret = true;
}
return ret;
}
bool WiFiClientSecureESP32::loadPrivateKey(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setPrivateKey(dest);
ret = true;
}
return ret;
}
int WiFiClientSecureESP32::lastError(char *buf, const size_t size)
{
if (!_lastError) {
return 0;
}
char error_buf[100];
mbedtls_strerror(_lastError, error_buf, 100);
snprintf(buf, size, "%s", error_buf);
return _lastError;
}
void WiFiClientSecureESP32::setHandshakeTimeout(unsigned long handshake_timeout)
{
sslclient->handshake_timeout = handshake_timeout * 1000;
}
void WiFiClientSecureESP32::setSTARTTLS(bool starttls)
{
sslclient->starttls = starttls;
}
void WiFiClientSecureESP32::setDebugCB(DebugMsgCallback cb)
{
sslclient->_debugCallback = std::move(cb);
}
#endif //ESP32
#endif //WiFiClientSecureESP32_CPP

View File

@ -0,0 +1,145 @@
/*
*Customized WiFiClientSecure.h to support STARTTLS protocol, version 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
WiFiClientSecureESP32.h - Base class that provides Client SSL to ESP32
Copyright (c) 2011 Adrian McEwen. All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WiFiClientSecureESP32_H
#define WiFiClientSecureESP32_H
#ifdef ESP32
#include "Arduino.h"
#include "IPAddress.h"
#include <WiFi.h>
#include "ssl_client32.h"
typedef void (*DebugMsgCallback)(const char* msg);
class WiFiClientSecureESP32 : public WiFiClient
{
protected:
sslclient_context32 *sslclient;
int _lastError = 0;
int _peek = -1;
int _timeout = 0;
const char *_CA_cert;
const char *_cert;
const char *_private_key;
const char *_pskIdent; // identity for PSK cipher suites
const char *_psKey; // key in hex for PSK cipher suites
DebugMsgCallback _debugCallback = NULL;
public:
WiFiClientSecureESP32 *next;
WiFiClientSecureESP32();
WiFiClientSecureESP32(int socket);
WiFiClientSecureESP32(bool starttls);
~WiFiClientSecureESP32();
int connect(IPAddress ip, uint16_t port);
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port);
int connect(const char *host, uint16_t port, int32_t timeout);
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
int peek();
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
int available();
int read();
int read(uint8_t *buf, size_t size);
void flush() {}
void stop();
uint8_t connected();
int lastError(char *buf, const size_t size);
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
void setCACert(const char *rootCA);
void setCertificate(const char *client_ca);
void setPrivateKey (const char *private_key);
bool loadCACert(Stream& stream, size_t size);
bool loadCertificate(Stream& stream, size_t size);
bool loadPrivateKey(Stream& stream, size_t size);
bool verify(const char* fingerprint, const char* domain_name);
void setHandshakeTimeout(unsigned long handshake_timeout);
void setSTARTTLS(bool starttls);
void setDebugCB(DebugMsgCallback cb);
operator bool()
{
return connected();
}
WiFiClientSecureESP32 &operator=(const WiFiClientSecureESP32 &other);
bool operator==(const bool value)
{
return bool() == value;
}
bool operator!=(const bool value)
{
return bool() != value;
}
bool operator==(const WiFiClientSecureESP32 &);
bool operator!=(const WiFiClientSecureESP32 &rhs)
{
return !this->operator==(rhs);
};
int socket()
{
return sslclient->socket = -1;
}
private:
char *_streamLoad(Stream& stream, size_t size);
//friend class WiFiServer;
using Print::write;
};
#endif //ESP32
#endif //WiFiClientSecureESP32_H

View File

@ -0,0 +1,853 @@
/*
*Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Provide SSL/TLS functions to ESP32 with Arduino IDE
*
* Adapted from the ssl_client1 example of mbedtls.
*
* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License.
* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License.
*/
#ifndef SSL_CLIENT32_CPP
#define SSL_CLIENT32_CPP
#ifdef ESP32
#include "Arduino.h"
#include <esp32-hal-log.h>
#include <lwip/err.h>
#include <lwip/sockets.h>
#include <lwip/sys.h>
#include <lwip/netdb.h>
#include <mbedtls/sha256.h>
#include <mbedtls/oid.h>
#include <algorithm>
#include <string>
#include "ssl_client32.h"
#include "WiFi.h"
const char *pers32 = "esp32-tls";
static int handle_error(int err)
{
if (err == -30848)
{
return err;
}
#ifdef MBEDTLS_ERROR_C
char error_buf[100];
mbedtls_strerror(err, error_buf, 100);
log_e("%s", error_buf);
#endif
log_e("MbedTLS message code: %d", err);
return err;
}
void ssl_init(sslclient_context32 *ssl_client)
{
mbedtls_ssl_init(&ssl_client->ssl_ctx);
mbedtls_ssl_config_init(&ssl_client->ssl_conf);
mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx);
mbedtls_net_init(&ssl_client->server_fd);
}
int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
{
char buf[512];
int ret, flags;
int enable = 1;
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_2, ssl_client);
log_v("Free internal heap before TLS %u", ESP.getFreeHeap());
log_v("Starting socket");
ssl_client->socket = -1;
ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ssl_client->socket < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_3, ssl_client);
log_e("ERROR opening socket");
return ssl_client->socket;
}
IPAddress srv((uint32_t)0);
if (!WiFiGenericClass::hostByName(host, srv))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_4, ssl_client);
return -1;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = srv;
serv_addr.sin_port = htons(port);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_5, ssl_client);
if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0)
{
if (timeout <= 0)
{
timeout = 30000;
}
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_6, ssl_client);
}
else
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_7, ssl_client);
log_e("Connect to Server failed!");
return -1;
}
fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK);
if (ssl_client->starttls && (port == 25 || port == 587 || port == 143))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_8, ssl_client);
if ((ret = starttlsHandshake(ssl_client, port)) != 0)
{
log_e("STARTTLS failed!");
return -1;
}
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_9, ssl_client);
log_v("Seeding the random number generator");
mbedtls_entropy_init(&ssl_client->entropy_ctx);
ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func,
&ssl_client->entropy_ctx, (const unsigned char *)pers32, strlen(pers32));
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_10, ssl_client);
log_v("Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&ssl_client->ssl_conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
// MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and
// MBEDTLS_SSL_VERIFY_NONE if not.
if (rootCABuff != NULL)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_11, ssl_client);
log_v("Loading CA cert");
mbedtls_x509_crt_init(&ssl_client->ca_cert);
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
ret = mbedtls_x509_crt_parse(&ssl_client->ca_cert, (const unsigned char *)rootCABuff, strlen(rootCABuff) + 1);
mbedtls_ssl_conf_ca_chain(&ssl_client->ssl_conf, &ssl_client->ca_cert, NULL);
//mbedtls_ssl_conf_verify(&ssl_client->ssl_ctx, my_verify, NULL );
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
}
else if (pskIdent != NULL && psKey != NULL)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_12, ssl_client);
log_v("Setting up PSK");
// convert PSK from hex to binary
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2 * MBEDTLS_PSK_MAX_LEN)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_13, ssl_client);
log_e("pre-shared key not valid hex or too long");
return -1;
}
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
size_t psk_len = strlen(psKey) / 2;
for (int j = 0; j < strlen(psKey); j += 2)
{
char c = psKey[j];
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'F')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'f')
c -= 'a' - 10;
else
return -1;
psk[j / 2] = c << 4;
c = psKey[j + 1];
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'F')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'f')
c -= 'a' - 10;
else
return -1;
psk[j / 2] |= c;
}
// set mbedtls config
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_14, ssl_client);
ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len,
(const unsigned char *)pskIdent, strlen(pskIdent));
if (ret != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
log_e("mbedtls_ssl_conf_psk returned %d", ret);
return handle_error(ret);
}
}
else
{
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
log_i("WARNING: Use certificates for a more secure communication!");
}
if (cli_cert != NULL && cli_key != NULL)
{
mbedtls_x509_crt_init(&ssl_client->client_cert);
mbedtls_pk_init(&ssl_client->client_key);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_15, ssl_client);
log_v("Loading CRT cert");
ret = mbedtls_x509_crt_parse(&ssl_client->client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1);
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_16, ssl_client);
log_v("Loading private key");
ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0);
if (ret != 0)
{
return handle_error(ret);
}
mbedtls_ssl_conf_own_cert(&ssl_client->ssl_conf, &ssl_client->client_cert, &ssl_client->client_key);
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_17, ssl_client);
log_v("Setting hostname for TLS session...");
// Hostname set here should match CN in server certificate
if ((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
mbedtls_ssl_conf_rng(&ssl_client->ssl_conf, mbedtls_ctr_drbg_random, &ssl_client->drbg_ctx);
if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_18, ssl_client);
log_v("Performing the SSL/TLS handshake...");
unsigned long handshake_start_time = millis();
while ((ret = mbedtls_ssl_handshake(&ssl_client->ssl_ctx)) != 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
return handle_error(ret);
}
if ((millis() - handshake_start_time) > ssl_client->handshake_timeout)
return -1;
vTaskDelay(10 / portTICK_PERIOD_MS);
}
if (cli_cert != NULL && cli_key != NULL)
{
log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx));
if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0)
{
log_d("Record expansion is %d", ret);
}
else
{
log_w("Record expansion is unknown (compression)");
}
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_19, ssl_client);
log_v("Verifying peer X.509 certificate...");
if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0)
{
bzero(buf, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_20, ssl_client);
log_e("Failed to verify peer certificate! verification info: %s", buf);
stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue.
return handle_error(ret);
}
else
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_21, ssl_client);
log_v("Certificate verified.");
}
if (rootCABuff != NULL)
{
mbedtls_x509_crt_free(&ssl_client->ca_cert);
}
if (cli_cert != NULL)
{
mbedtls_x509_crt_free(&ssl_client->client_cert);
}
if (cli_key != NULL)
{
mbedtls_pk_free(&ssl_client->client_key);
}
log_v("Free internal heap after TLS %u", ESP.getFreeHeap());
return ssl_client->socket;
}
void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_22, ssl_client);
log_v("Cleaning SSL connection.");
if (ssl_client->socket >= 0)
{
close(ssl_client->socket);
ssl_client->socket = -1;
}
mbedtls_ssl_free(&ssl_client->ssl_ctx);
mbedtls_ssl_config_free(&ssl_client->ssl_conf);
mbedtls_ctr_drbg_free(&ssl_client->drbg_ctx);
mbedtls_entropy_free(&ssl_client->entropy_ctx);
}
int data_to_read(sslclient_context32 *ssl_client)
{
int ret, res;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0);
//log_e("RET: %i",ret); //for low level debug
res = mbedtls_ssl_get_bytes_avail(&ssl_client->ssl_ctx);
//log_e("RES: %i",res); //for low level debug
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0)
{
if (ssl_client->_debugCallback)
{
char *buf = new char[512];
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
delete[] buf;
}
return handle_error(ret);
}
return res;
}
int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len)
{
log_v("Writing HTTP request..."); //for low level debug
int ret = -1;
while ((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
return handle_error(ret);
}
}
len = ret;
//log_v("%d bytes written", len); //for low level debug
return ret;
}
int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length)
{
//log_d( "Reading HTTP response..."); //for low level debug
int ret = -1;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length);
//log_v( "%d bytes read", ret); //for low level debug
return ret;
}
static bool parseHexNibble(char pb, uint8_t *res)
{
if (pb >= '0' && pb <= '9')
{
*res = (uint8_t)(pb - '0');
return true;
}
else if (pb >= 'a' && pb <= 'f')
{
*res = (uint8_t)(pb - 'a' + 10);
return true;
}
else if (pb >= 'A' && pb <= 'F')
{
*res = (uint8_t)(pb - 'A' + 10);
return true;
}
return false;
}
// Compare a name from certificate and domain name, return true if they match
static bool matchName(const std::string &name, const std::string &domainName)
{
size_t wildcardPos = name.find('*');
if (wildcardPos == std::string::npos)
{
// Not a wildcard, expect an exact match
return name == domainName;
}
size_t firstDotPos = name.find('.');
if (wildcardPos > firstDotPos)
{
// Wildcard is not part of leftmost component of domain name
// Do not attempt to match (rfc6125 6.4.3.1)
return false;
}
if (wildcardPos != 0 || firstDotPos != 1)
{
// Matching of wildcards such as baz*.example.com and b*z.example.com
// is optional. Maybe implement this in the future?
return false;
}
size_t domainNameFirstDotPos = domainName.find('.');
if (domainNameFirstDotPos == std::string::npos)
{
return false;
}
return domainName.substr(domainNameFirstDotPos) == name.substr(firstDotPos);
}
// Verifies certificate provided by the peer to match specified SHA256 fingerprint
bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, const char *domain_name)
{
// Convert hex string to byte array
uint8_t fingerprint_local[32];
int len = strlen(fp);
int pos = 0;
for (size_t i = 0; i < sizeof(fingerprint_local); ++i)
{
while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':')))
{
++pos;
}
if (pos > len - 2)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_23, ssl_client);
log_d("pos:%d len:%d fingerprint too short", pos, len);
return false;
}
uint8_t high, low;
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_24, ssl_client);
log_d("pos:%d len:%d invalid hex sequence: %c%c", pos, len, fp[pos], fp[pos + 1]);
return false;
}
pos += 2;
fingerprint_local[i] = low | (high << 4);
}
// Get certificate provided by the peer
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
if (!crt)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_25, ssl_client);
log_d("could not fetch peer certificate");
return false;
}
// Calculate certificate's SHA256 fingerprint
uint8_t fingerprint_remote[32];
mbedtls_sha256_context sha256_ctx;
mbedtls_sha256_init(&sha256_ctx);
mbedtls_sha256_starts(&sha256_ctx, false);
mbedtls_sha256_update(&sha256_ctx, crt->raw.p, crt->raw.len);
mbedtls_sha256_finish(&sha256_ctx, fingerprint_remote);
// Check if fingerprints match
if (memcmp(fingerprint_local, fingerprint_remote, 32))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_26, ssl_client);
log_d("fingerprint doesn't match");
return false;
}
// Additionally check if certificate has domain name if provided
if (domain_name)
return verify_ssl_dn(ssl_client, domain_name);
else
return true;
}
// Checks if peer certificate has specified domain in CN or SANs
bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name)
{
log_d("domain name: '%s'", (domain_name) ? domain_name : "(null)");
std::string domain_name_str(domain_name);
std::transform(domain_name_str.begin(), domain_name_str.end(), domain_name_str.begin(), ::tolower);
// Get certificate provided by the peer
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
// Check for domain name in SANs
const mbedtls_x509_sequence *san = &crt->subject_alt_names;
while (san != nullptr)
{
std::string san_str((const char *)san->buf.p, san->buf.len);
std::transform(san_str.begin(), san_str.end(), san_str.begin(), ::tolower);
if (matchName(san_str, domain_name_str))
return true;
log_d("SAN '%s': no match", san_str.c_str());
// Fetch next SAN
san = san->next;
}
// Check for domain name in CN
const mbedtls_asn1_named_data *common_name = &crt->subject;
while (common_name != nullptr)
{
// While iterating through DN objects, check for CN object
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &common_name->oid))
{
std::string common_name_str((const char *)common_name->val.p, common_name->val.len);
if (matchName(common_name_str, domain_name_str))
return true;
log_d("CN '%s': not match", common_name_str.c_str());
}
// Fetch next DN object
common_name = common_name->next;
}
return false;
}
int starttlsHandshake(sslclient_context32 *ssl_client, int port)
{
int ret = 0;
size_t msgLen = 100;
size_t bufLen = 512;
char *buf = new char[bufLen];
char *hMsg = new char[msgLen];
fd_set readset;
fd_set writeset;
fd_set errset;
struct timeval tv;
FD_ZERO(&readset);
FD_SET(ssl_client->socket, &readset);
FD_ZERO(&writeset);
FD_SET(ssl_client->socket, &writeset);
FD_ZERO(&errset);
FD_SET(ssl_client->socket, &errset);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_27, ssl_client);
goto starttls_exit;
}
ret = read(ssl_client->socket, buf, bufLen);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_28, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
}
if (port == 587 || port == 25)
{
memset(hMsg, 0, msgLen);
strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_29);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_30, ssl_client);
ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_31, ssl_client);
goto starttls_exit;
}
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_32, ssl_client);
goto starttls_exit;
}
memset(buf, 0, bufLen);
ret = lwip_read(ssl_client->socket, buf, bufLen);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_33, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
}
}
memset(hMsg, 0, msgLen);
strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_34);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_35, ssl_client);
ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_36, ssl_client);
goto starttls_exit;
}
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_37, ssl_client);
goto starttls_exit;
}
memset(buf, 0, bufLen);
ret = lwip_read(ssl_client->socket, buf, bufLen);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_38, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
}
delete[] buf;
delete[] hMsg;
return 0;
starttls_exit:
delete[] buf;
delete[] hMsg;
return -1;
}
void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client)
{
size_t dbgInfoLen = strlen_P(info) + 1;
char *dbgInfo = new char[dbgInfoLen];
memset(dbgInfo, 0, dbgInfoLen);
strcpy_P(dbgInfo, info);
ssl_client->_debugCallback(dbgInfo);
delete[] dbgInfo;
}
#endif //ESP32
#endif //SSL_CLIENT32_CPP

View File

@ -0,0 +1,116 @@
/*
*Customized ssl_client.h to support STARTTLS protocol, version 1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Provide SSL/TLS functions to ESP32 with Arduino IDE
* by Evandro Copercini - 2017 - Apache 2.0 License
*/
#ifndef SSL_CLIENT32_H
#define SSL_CLIENT32_H
#ifdef ESP32
#include "mbedtls/platform.h"
#include "mbedtls/net.h"
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
static const char ESP32_SSL_CLIENT_STR_1[] PROGMEM = "ERROR: ";
static const char ESP32_SSL_CLIENT_STR_2[] PROGMEM = "INFO: starting socket";
static const char ESP32_SSL_CLIENT_STR_3[] PROGMEM = "ERROR: opening socket";
static const char ESP32_SSL_CLIENT_STR_4[] PROGMEM = "ERROR: could not get ip from host";
static const char ESP32_SSL_CLIENT_STR_5[] PROGMEM = "INFO: connecting to Server...";
static const char ESP32_SSL_CLIENT_STR_6[] PROGMEM = "INFO: server connected";
static const char ESP32_SSL_CLIENT_STR_7[] PROGMEM = "ERROR: connect to Server failed!";
static const char ESP32_SSL_CLIENT_STR_8[] PROGMEM = "INFO: begin STARTTLS handshake";
static const char ESP32_SSL_CLIENT_STR_9[] PROGMEM = "INFO: seeding the random number generator";
static const char ESP32_SSL_CLIENT_STR_10[] PROGMEM = "INFO: setting up the SSL/TLS structure...";
static const char ESP32_SSL_CLIENT_STR_11[] PROGMEM = "INFO: loading CA cert";
static const char ESP32_SSL_CLIENT_STR_12[] PROGMEM = "INFO: setting up PSK";
static const char ESP32_SSL_CLIENT_STR_13[] PROGMEM = "ERROR: pre-shared key not valid hex or too long";
static const char ESP32_SSL_CLIENT_STR_14[] PROGMEM = "INFO: set mbedtls config";
static const char ESP32_SSL_CLIENT_STR_15[] PROGMEM = "INFO: loading CRT cert";
static const char ESP32_SSL_CLIENT_STR_16[] PROGMEM = "INFO: loading private key";
static const char ESP32_SSL_CLIENT_STR_17[] PROGMEM = "INFO: setting hostname for TLS session...";
static const char ESP32_SSL_CLIENT_STR_18[] PROGMEM = "INFO: performing the SSL/TLS handshake...";
static const char ESP32_SSL_CLIENT_STR_19[] PROGMEM = "INFO: verifying peer X.509 certificate...";
static const char ESP32_SSL_CLIENT_STR_20[] PROGMEM = "ERROR: failed to verify peer certificate!";
static const char ESP32_SSL_CLIENT_STR_21[] PROGMEM = "INFO: certificate verified";
static const char ESP32_SSL_CLIENT_STR_22[] PROGMEM = "INFO: cleaning SSL connection";
static const char ESP32_SSL_CLIENT_STR_23[] PROGMEM = "ERROR: fingerprint too short";
static const char ESP32_SSL_CLIENT_STR_24[] PROGMEM = "ERROR: invalid hex sequence";
static const char ESP32_SSL_CLIENT_STR_25[] PROGMEM = "ERROR: could not fetch peer certificate";
static const char ESP32_SSL_CLIENT_STR_26[] PROGMEM = "ERROR: fingerprint doesn't match";
static const char ESP32_SSL_CLIENT_STR_27[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_28[] PROGMEM = "ERROR: reading incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_29[] PROGMEM = "EHLO DUDE\r\n";
static const char ESP32_SSL_CLIENT_STR_30[] PROGMEM = "INFO: send SMTP command extended HELO";
static const char ESP32_SSL_CLIENT_STR_31[] PROGMEM = "ERROR: send SMTP command failed!";
static const char ESP32_SSL_CLIENT_STR_32[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_33[] PROGMEM = "ERROR: reading incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_34[] PROGMEM = "STARTTLS\r\n";
static const char ESP32_SSL_CLIENT_STR_35[] PROGMEM = "INFO: send STARTTLS protocol command";
static const char ESP32_SSL_CLIENT_STR_36[] PROGMEM = "ERROR: send STARTTLS protocol command failed!";
static const char ESP32_SSL_CLIENT_STR_37[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_38[] PROGMEM = "ERROR: reading incoming data failed!";
typedef void (*DebugMsgCallback)(const char *msg);
typedef struct sslclient_context32 {
int socket;
bool starttls;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
mbedtls_net_context server_fd;
mbedtls_ctr_drbg_context drbg_ctx;
mbedtls_entropy_context entropy_ctx;
mbedtls_x509_crt ca_cert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
DebugMsgCallback _debugCallback;
unsigned long handshake_timeout;
} sslclient_context32;
void ssl_init(sslclient_context32 *ssl_client);
int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int data_to_read(sslclient_context32 *ssl_client);
int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len);
int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length);
bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char* fp, const char* domain_name);
bool verify_ssl_dn(sslclient_context32 *ssl_client, const char* domain_name);
int starttlsHandshake(sslclient_context32 *ssl_client, int port);
void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client);
#endif //ESP32
#endif //SSL_CLIENT32_H