Https client gets cpp-netlib using client certificate and password
I'm trying to use cppnetlib or even the boost asio libraries to connect to make a simple url and pull the resulting page.
I got it to work with http and even https usign cppnetlib, but I need to provide a client certificate that takes the password. Unforntuntley I need to use the old v0.10 cppnetlib.
Is it possible to do this. I think the answer is to create your own _io_service and custome configure it to request https with certificate and password and then pass it to the boost :: network :: http: client constructor. The following works for http, and will work for https without requiring a certificate.
std::string url = "http://www.boost.org";
std::string certFile = "C:\\cert\\mycert.p12";
std::string password = "MyPassWord";
try {
http::client client;
http::client::request request(url);
http::client::response response = client->get(request);
std::string resultText = static_cast<std::string>(body(response));
std::cout << resultText << std::endl;
delete client;
}
catch (std::exception &e) {
std::cerr << "Caught something connecting " << e.what() << std::endl;
}
source to share
v0.10 cppnetlib does not directly support client certificates. Since you are using cppnetleb you can use boost asio with boost 1.49
Here is some sample code that does most of the asio work https://github.com/alexandruc/SimpleHttpsClient/blob/master/https_client.cpp
This code is very similar to http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/example/ssl/client.cpp
I put both in case of broken links. To manage the https client to complete client certification, you need to add the following main lines before creating the client:
std::string tempString = "test.pem"; //this is a pem file that contains a private key and a certificate.
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23_client);
ctx.set_options(boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::no_sslv3);
ctx.set_default_verify_paths();
ctx.use_certificate_file(tempFileStr.c_str(), boost::asio::ssl::context_base::pem);
ctx.use_private_key_file(tempFileStr.c_str(), boost::asio::ssl::context_base::pem);
However, in this example, you don't have a PEM file other than a p12 file (pkcs12 format). openssl can be used to decrypt and create a deisred pem file. I adapted the code from How to load PKCS # 12 file in OpenSSL programmatically? Undoubtedly this version of boost does not support in-memory certificates, so it must be written dycrypted to the file. I put this in a temporary directory and it should probably be removed at the end.
std::string _certFile = "C:\\cert\\mycert.p12";
std::string password = "_certPassword";
boost::filesystem::path tempFile = boost::filesystem::temp_directory_path() / "temp.pem";
std::string tempFileStr = tempFile.generic_string();
std::cout<<"Using temp file " << tempFileStr<<std::endl;
try
{
//read in the pksc12 file, decode it and write a PEM file
FILE *fp;
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
int i;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
if (!(fp = fopen(_certFile.c_str(), "rb"))) {
fprintf(stderr, "Error opening file %s\n", _certFile);
return false;
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
return false;
}
if (!PKCS12_parse(p12, _certpPassword.c_str(), &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
return false;
}
PKCS12_free(p12);
if (!(fp = fopen(tempFileStr.c_str(), "w"))) {
fprintf(stderr, "Error opening file %s\n", tempFileStr.c_str());
return false;
}
if (pkey) {
fprintf(fp, "***Private Key***\n");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
}
if (cert) {
fprintf(fp, "***User Certificate***\n");
PEM_write_X509(fp, cert);
}
if (ca && sk_X509_num(ca)) {
fprintf(fp, "***Other Certificates***\n");
for (i = 0; i < sk_X509_num(ca); i++)
{
PEM_write_X509(fp, sk_X509_value(ca, i));
}
}
sk_X509_pop_free(ca, X509_free);
X509_free(cert);
EVP_PKEY_free(pkey);
fclose(fp);
}
catch (std::exception &e) {
retVal = false;
std::cout <<"Error parsing/decrypting pkcs12 file into PEM or writing temporary pem file" << e.what() << std::endl;
}
Here are the inclusions I used
//for ssl connection
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/ssl/context_base.hpp>
//for parsing key file
#include <openssl/pkcs12.h>
source to share