浏览代码

Teach Libssl backend to load .p12 files

Nils Maier 12 年之前
父节点
当前提交
f7b0fbbf53
共有 4 个文件被更改,包括 96 次插入17 次删除
  1. 92 0
      src/LibsslTLSContext.cc
  2. 1 0
      src/LibsslTLSContext.h
  3. 1 5
      src/MultiUrlRequestInfo.cc
  4. 2 12
      src/OptionHandlerFactory.cc

+ 92 - 0
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()
 {

+ 1 - 0
src/LibsslTLSContext.h

@@ -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;
 

+ 1 - 5
src/MultiUrlRequestInfo.cc

@@ -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.");
       }

+ 2 - 12
src/OptionHandlerFactory.cc

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