Skip to content

Add CramMD5 auth #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion EMailSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@

#include "EMailSender.h"
#include <stdio.h>
#if defined(ESP32)
#include <mbedtls/base64.h>
#endif

//#include <SPIFFS.h>
//#include <LittleFS.h>

Expand Down Expand Up @@ -624,7 +628,70 @@ EMailSender::Response EMailSender::send(const char* to[], byte sizeOfTo, byte s
// String auth = "AUTH PLAIN "+String(encode64(logPass));
DEBUG_PRINTLN(auth);
client.println(auth);
}else{
}
#if defined(ESP32)
else if (this->isCramMD5Login == true) {
DEBUG_PRINTLN(F("AUTH CRAM-MD5"));
client.println(F("AUTH CRAM-MD5"));

// read back the base64 encoded digest.
//
response = awaitSMTPResponse(client,"334","No digest error");
if (!response.status) {
client.flush();
client.stop();
return response;
};
_serverResponce = _serverResponce.substring(4); // '334<space>'

size_t b64l = _serverResponce.length()-1; // C vs C++ counting of \0
const unsigned char * b64 = (const unsigned char *)_serverResponce.c_str();
DEBUG_PRINTLN("B64digest="+String((char *)b64) + " Len=" + String((int)b64l));

unsigned char digest[256];
size_t len;

int e = mbedtls_base64_decode(digest, sizeof(digest), &len, b64, b64l);
if (e || len < 3 || len >= 256) {
response.code = F("999");
response.desc = F("Invalid digest");
response.status = false;
client.flush();
client.stop();
return response;
};

// calculate HMAC with the password as the key of this digest.
//
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_MD5;
unsigned char md5[16];

mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
mbedtls_md_hmac_starts(&ctx,
(const unsigned char *)this->email_password, strlen(this->email_password));
mbedtls_md_hmac_update(&ctx, digest, len);
mbedtls_md_hmac_finish(&ctx, md5);
mbedtls_md_free(&ctx);

// build an output string of the username followed by the __lowercase__ hex of the md5
//
String rsp = String(this->email_login) + " ";
for(int i = 0; i < sizeof(md5); i++) {
unsigned char c = md5[i];
char h[16+1] = "0123456789abcdef";
rsp += String(h[ (c >> 4) &0xF]) + String(h[ (c >> 0) &0xF]);
};

// And submit this to the server as a login string.
DEBUG_PRINTLN(encode64((char*)rsp.c_str()));
client.println(encode64((char*)rsp.c_str()));

// now exepct the normal login confirmation to continue.
}
#endif
else{
DEBUG_PRINTLN(F("AUTH LOGIN:"));
client.println(F("AUTH LOGIN"));
awaitSMTPResponse(client);
Expand Down
8 changes: 8 additions & 0 deletions EMailSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,13 @@ class EMailSender {
this->isSASLLogin = isSASLLogin;
}

#if defined(ESP32)
// Conditional - as it relies on considerable crypto infra.
void setCramMD5Login(bool onoff= false) {
this->isCramMD5Login = onoff;
}
#endif

void setAdditionalResponseLineOnConnection(uint8_t numLines = 0) {
this->additionalResponseLineOnConnection = numLines;
}
Expand All @@ -485,6 +492,7 @@ class EMailSender {
bool isSASLLogin = false;

bool useAuth = true;
bool isCramMD5Login = false;

String _serverResponce;

Expand Down