summaryrefslogtreecommitdiff
path: root/src/LibsslTLSContext.cc
diff options
context:
space:
mode:
authorNils Maier <maierman@web.de>2013-09-22 12:14:51 +0200
committerNils Maier <maierman@web.de>2013-09-22 12:55:27 +0200
commitf7b0fbbf532bdce896b1f2a1bdf3bdd0acdb88e6 (patch)
tree5cfb133a1f8f085ee095c2fe131bd54b90cb1a80 /src/LibsslTLSContext.cc
parent08e2e412dc562513d48900c071707a3cccb9c22f (diff)
Teach Libssl backend to load .p12 files
Diffstat (limited to 'src/LibsslTLSContext.cc')
-rw-r--r--src/LibsslTLSContext.cc92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/LibsslTLSContext.cc b/src/LibsslTLSContext.cc
index c0507227..6f59a5d4 100644
--- a/src/LibsslTLSContext.cc
+++ b/src/LibsslTLSContext.cc
@@ -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()
{