Sign in to follow this  
fitfool

[C++] Implementing SSL

Recommended Posts

fitfool    113
Hello, im developing an application that needs to be able to send emails. Unfortunately, almost all large free email providers(Gmail, Hotmail etc.) require encryption over SSL/TLS. I'm looking to possibly implement this myself. I've looked over a few librarys such as OpenSSL and yaSSL. The documentation isn't too great for either of these, and i've looked over some sample code in yaSSL, and it seems to require a certificate file, which I do not want to have to distribute. Anyways, I was basically asking if you guys know of a library of which has the following propertys: 1. Statically linkable. 2. Not dependant on certificate files, or any other external dependencies. 3. Win32/64 compatible. 4. Hopefully, easy to implement. :) Or, if I were to implement SSL myself on top of my socket wrapper, I was looking for a helpful resource on the knitty-gritty implementation details. Of course, I've used google, but maybe there's the holy grail of resources out there I don't know about. Reading over RFCs is never fun and always seems to be a cryptic process. Thanks.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
You should be able to use cURL for your task. It comes with optional support for SSL, so make sure to download the SSL version for the 32bit and 64bit packages. It also comes with static libraries as well as source that you can use if needed. However, OpenSSL is provided as a DLL so you would need to spend some time putting it all together if you wanted absolutely no DLLs.

I hacked together a simple (32bit) e-mail retrieving program based on this PHP cURL code to see how it was using cURL and it was pretty easy.


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <time.h>
#include <curl/curl.h>

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
std::string base64_decode(std::string const& encoded_string);

std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim);

int main(int argc, char * argv[])
{
const std::string g_username = "";
const std::string g_password = "";

CURL * curl;
CURLcode result;

curl_slist * headers = 0;

curl_global_init(CURL_GLOBAL_ALL);

curl = curl_easy_init();

result = curl_easy_setopt(curl, CURLOPT_URL, "https://gmail.google.com/gmail/feed/atom");
if(result == CURLE_OK)
{

headers = curl_slist_append(headers, "Host: gmail.google.com");
std::stringstream ss0;
ss0 << g_username << ":" << g_password;
std::stringstream ss1;
ss1 << "Authorization: Basic " << base64_encode(reinterpret_cast<const unsigned char *>(ss0.str().c_str()), ss0.str().size());
headers = curl_slist_append(headers, ss1.str().c_str());
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4");
headers = curl_slist_append(headers, "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
headers = curl_slist_append(headers, "Accept-Language: en-gb,en;q=0.5");
headers = curl_slist_append(headers, "Accept-Encoding: text");
headers = curl_slist_append(headers, "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7");

time_t rawtime;
struct tm * timeinfo = 0;
tm * ptm = 0;

time(&rawtime);
timeinfo = localtime(&rawtime);
std::vector<std::string> tokens = TokenizeString(asctime(timeinfo), " \n");

char outb[32] = {0};
ptm = gmtime(&rawtime);
_snprintf_s(outb, 32, 31, "%2d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

std::stringstream ss3;
ss3 << "Date: " << tokens[0] << ", " << tokens[2] << " " << tokens[1] << " " << tokens[4] << " " << outb << " " << "GMT";

headers = curl_slist_append(headers, ss3.str().c_str());

curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl, CURLOPT_COOKIESESSION, true);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, 1);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);

result = curl_easy_perform(curl);

curl_slist_free_all(headers);
headers = NULL;
}

curl_global_cleanup();

return 0;
}

// Tokenizes a string into a vector
std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim)
{
// http://www.gamedev.net/community/forums/topic.asp?topic_id=381544#TokenizeString
using namespace std;
vector<string> tokens;
size_t p0 = 0, p1 = string::npos;
while(p0 != string::npos)
{
p1 = str.find_first_of(delim, p0);
if(p1 != p0)
{
string token = str.substr(p0, p1 - p0);
tokens.push_back(token);
}
p0 = str.find_first_not_of(delim, p1);
}
return tokens;
}

/*
base64.cpp and base64.h

Copyright (C) 2004-2008 René Nyffenegger

This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.

3. This notice may not be removed or altered from any source distribution.

René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/


static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static inline bool is_base64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++);
if(i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if(i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}

std::string base64_decode(std::string const& encoded_string)
{
int in_len = (int)encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::stringstream ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4)
{
for (i = 0; i <4; i++)
char_array_4[i] = (unsigned char)base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret << char_array_3[i];
i = 0;
}
}
if(i)
{
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = (unsigned char)base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
ret << char_array_3[j];
}
return ret.str();
}




It also worked quite nicely on the first try!:


So, perhaps you could use it as a starting point. You can also look into an application packer that bundles DLLs as well if you only wanted one final file to distribute as well, such as MoleBox.

I've not tried the e-mail sending logic or other e-mail sites, but since this works very easily with Gmail over SSL for retrieving, I'd strongly suspect it'll work with others as well. That will be up to you to verify though. [wink] Goodluck!

Share this post


Link to post
Share on other sites
fitfool    113
Thanks for you replys.

I'm actually looking to implement SMTP with the SSL extension. So I don't think curl will be of too much help. Has anyone used Asio's SSL capabilities? I already have a winsock wrapper. How hard would it be to build Asios SLL-ness on top of it? Is there any way to have Asio use my socket descriptor?

Thanks.

Share this post


Link to post
Share on other sites
cache_hit    614
Nothing about boost is really easy until you've struggled with it for a couple days.

It appears you can construct a boost::asio socket from a native socket using the following overload:

http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload4.html


However, I haven't used its SSL capabilities so I can't tell you really how to proceed from there. I'm pretty sure the whole thing is possible though, and once you get past the learning curve it's probably elegant and intuitive.

Share this post


Link to post
Share on other sites
fitfool    113
Just for anyone facing similar issues in the future, I ended up going with CyaSSL. It's lightweight and very easy to work with. Just check out their examples.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this