Teach Libssl backend to load .p12 files

pull/128/head
Nils Maier 2013-09-22 12:14:51 +02:00
parent 08e2e412dc
commit f7b0fbbf53
4 changed files with 96 additions and 17 deletions

View File

@ -34,12 +34,30 @@
/* copyright --> */
#include "LibsslTLSContext.h"
#include <sstream>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/bio.h>
#include "LogFactory.h"
#include "Logger.h"
#include "fmt.h"
#include "message.h"
#include "BufferedFile.h"
namespace {
struct bio_deleter {
void operator()(BIO *b) {
if (b) BIO_free(b);
}
};
struct p12_deleter {
void operator()(PKCS12 *p) {
if (p) PKCS12_free(p);
}
};
} // namespace
namespace aria2 {
@ -88,6 +106,9 @@ bool OpenSSLTLSContext::good() const
bool OpenSSLTLSContext::addCredentialFile(const std::string& certfile,
const std::string& keyfile)
{
if (keyfile.empty()) {
return addP12CredentialFile(certfile);
}
if(SSL_CTX_use_PrivateKey_file(sslCtx_, keyfile.c_str(),
SSL_FILETYPE_PEM) != 1) {
A2_LOG_ERROR(fmt("Failed to load private key from %s. Cause: %s",
@ -106,6 +127,77 @@ bool OpenSSLTLSContext::addCredentialFile(const std::string& certfile,
keyfile.c_str()));
return true;
}
bool OpenSSLTLSContext::addP12CredentialFile(const std::string& p12file)
{
// Need this to "decrypt" p12 files.
OpenSSL_add_all_algorithms();
std::stringstream ss;
BufferedFile(p12file.c_str(), "rb").transfer(ss);
void *ptr = const_cast<char*>(ss.str().c_str());
size_t len = ss.str().length();
std::unique_ptr<BIO, bio_deleter> bio(BIO_new_mem_buf(ptr, len));
A2_LOG_DEBUG(fmt("p12 size: %" PRIu64, len));
if (!bio) {
A2_LOG_ERROR("Failed to open p12 file: no memory");
return false;
}
std::unique_ptr<PKCS12, p12_deleter> p12(d2i_PKCS12_bio(bio.get(), nullptr));
if (!p12) {
A2_LOG_ERROR(fmt("Failed to open p12 file: %s",
ERR_error_string(ERR_get_error(), nullptr)));
return false;
}
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = 0;
if (!PKCS12_parse(p12.get(), "", &pkey, &cert, &ca)) {
A2_LOG_ERROR(fmt("Failed to parse p12 file: %s",
ERR_error_string(ERR_get_error(), nullptr)));
return false;
}
bool rv = false;
if (pkey && cert) {
rv = SSL_CTX_use_PrivateKey(sslCtx_, pkey);
if (!rv) {
A2_LOG_ERROR(fmt("Failed to use p12 file pkey: %s",
ERR_error_string(ERR_get_error(), nullptr)));
}
if (rv) {
rv = SSL_CTX_use_certificate(sslCtx_, cert);
if (!rv) {
A2_LOG_ERROR(fmt("Failed to use p12 file cert: %s",
ERR_error_string(ERR_get_error(), nullptr)));
}
}
if (rv && ca && sk_X509_num(ca)) {
rv = SSL_CTX_add_extra_chain_cert(sslCtx_, ca);
if (!rv) {
A2_LOG_ERROR(fmt("Failed to use p12 file chain: %s",
ERR_error_string(ERR_get_error(), nullptr)));
}
}
}
else {
A2_LOG_ERROR(fmt("Failed to use p12 file: no pkey or cert %s",
ERR_error_string(ERR_get_error(), nullptr)));
}
if (pkey) EVP_PKEY_free(pkey);
if (cert) X509_free(cert);
if (ca) sk_X509_pop_free(ca, X509_free);
if (!rv) {
A2_LOG_ERROR(fmt("Failed to use p12 file: %s",
ERR_error_string(ERR_get_error(), nullptr)));
}
else {
A2_LOG_INFO("Using certificate and key from p12 file");
}
return rv;
}
bool OpenSSLTLSContext::addSystemTrustedCACerts()
{

View File

@ -55,6 +55,7 @@ public:
// private key `keyfile' must be decrypted.
virtual bool addCredentialFile(const std::string& certfile,
const std::string& keyfile) CXX11_OVERRIDE;
virtual bool addP12CredentialFile(const std::string& p12file);
virtual bool addSystemTrustedCACerts() CXX11_OVERRIDE;

View File

@ -181,11 +181,7 @@ int MultiUrlRequestInfo::prepare()
#ifdef ENABLE_SSL
if(option_->getAsBool(PREF_ENABLE_RPC) &&
option_->getAsBool(PREF_RPC_SECURE)) {
if(option_->blank(PREF_RPC_CERTIFICATE)
#ifndef HAVE_APPLETLS
|| option_->blank(PREF_RPC_PRIVATE_KEY)
#endif // HAVE_APPLETLS
) {
if(option_->blank(PREF_RPC_CERTIFICATE)) {
throw DL_ABORT_EX("Specify --rpc-certificate and --rpc-private-key "
"options in order to use secure RPC.");
}

View File

@ -792,20 +792,10 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
handlers.push_back(op);
}
{
OptionHandler* op(
#ifdef HAVE_APPLETLS
new DefaultOptionHandler
OptionHandler* op(new DefaultOptionHandler
(PREF_RPC_CERTIFICATE,
TEXT_RPC_CERTIFICATE,
NO_DEFAULT_VALUE)
#else // HAVE_APPLETLS
new LocalFilePathOptionHandler
(PREF_RPC_CERTIFICATE,
TEXT_RPC_CERTIFICATE,
NO_DEFAULT_VALUE,
false)
#endif
);
NO_DEFAULT_VALUE));
op->addTag(TAG_RPC);
handlers.push_back(op);
}