[M108 Migration][VD] Support Root/Client/webSDI/Dynamic Certificate 87/289587/4 submit/tizen/20230320.160014
authorjingjieli <jingjie.li@samsung.com>
Fri, 10 Mar 2023 04:32:46 +0000 (12:32 +0800)
committerBot Blink <blinkbot@samsung.com>
Mon, 20 Mar 2023 10:58:40 +0000 (10:58 +0000)
- Introduce WebSDI and Mutual Authenticate Feature.
- Add Dynamic Certificate Feature.
- Refactoring root Certificate & WRT client Certificate.
- Remove duplicate functions of certificate loading.
- Refactoring the client certificate selection code for WRT.
- Change the kDefaultCertPublic path and kDefaultCertPrivate.
- DefaultClientCert path setting based on Tizen version

This patch is migrated from Tizen7.0:
https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/281524/

Change-Id: Ic401ea8f94d02b2f7b7d9d383bc03c99092d9bf7
Signed-off-by: jingjieli <jingjie.li@samsung.com>
21 files changed:
content/browser/ssl/ssl_client_auth_handler.cc
content/browser/web_contents/web_contents_impl.cc
content/browser/web_contents/web_contents_impl.h
content/public/browser/content_browser_client.h
content/public/browser/web_contents.h
crypto/ec_private_key.cc
crypto/ec_private_key.h
net/cert/cert_database.cc
net/cert/cert_database.h
tizen_src/chromium_impl/content/browser/browser_efl.gni
tizen_src/chromium_impl/content/public/browser/certificates_utils.cc [new file with mode: 0644]
tizen_src/chromium_impl/content/public/browser/certificates_utils.h [new file with mode: 0644]
tizen_src/ewk/efl_integration/BUILD.gn
tizen_src/ewk/efl_integration/browser_context_efl.cc
tizen_src/ewk/efl_integration/browser_context_efl.h
tizen_src/ewk/efl_integration/content_browser_client_efl.cc
tizen_src/ewk/efl_integration/content_browser_client_efl.h
tizen_src/ewk/efl_integration/eweb_view.cc
tizen_src/ewk/efl_integration/eweb_view.h
tizen_src/ewk/efl_integration/public/ewk_context.cc
tizen_src/ewk/efl_integration/public/ewk_view.cc

index 9bb0867..f02ea23 100644 (file)
@@ -139,7 +139,7 @@ void SSLClientAuthHandler::DidGetClientCerts(
     delegate_->CancelCertificateSelection();
     return;
   }
-
+#if !BUILDFLAG(IS_TIZEN_TV)
   // Note that if |client_cert_store_| is NULL, we intentionally fall through to
   // SelectClientCertificate(). This is for platforms where the client cert
   // matching is not performed by Chrome. Those platforms handle the cert
@@ -149,6 +149,9 @@ void SSLClientAuthHandler::DidGetClientCerts(
     delegate_->ContinueWithCertificate(nullptr, nullptr);
     return;
   }
+#else
+  LOG(INFO) << "Try to get client certificates";
+#endif
 
   // SelectClientCertificate() may call back into |delegate_| synchronously and
   // destroy this object, so guard the cancellation callback logic by a WeakPtr.
index 2a9fcfc..1e39df3 100644 (file)
@@ -8425,6 +8425,13 @@ bool WebContentsImpl::CompletedFirstVisuallyNonEmptyPaint() {
   return GetPrimaryPage().did_first_visually_non_empty_paint();
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void WebContentsImpl::AddDynamicCertificatePath(const std::string& host,
+                                                const std::string& cert_path) {
+  GetContentClient()->browser()->AddDynamicCertificatePath(host, cert_path);
+}
+#endif
+
 void WebContentsImpl::OnDidDownloadImage(
     base::WeakPtr<RenderFrameHostImpl> rfh,
     ImageDownloadCallback callback,
index e84c8aa..72a53a7 100644 (file)
@@ -591,6 +591,10 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
   service_manager::InterfaceProvider* GetJavaInterfaces() override;
 #endif
   bool HasRecentInteractiveInputEvent() override;
+#if BUILDFLAG(IS_TIZEN_TV)
+  void AddDynamicCertificatePath(const std::string& host,
+                                 const std::string& cert_path) override;
+#endif
   void SetIgnoreInputEvents(bool ignore_input_events) override;
   bool HasActiveEffectivelyFullscreenVideo() override;
   void WriteIntoTrace(perfetto::TracedValue context) override;
index f7768ad..e7797f6 100644 (file)
@@ -984,6 +984,14 @@ class CONTENT_EXPORT ContentBrowserClient {
       net::ClientCertIdentityList client_certs,
       std::unique_ptr<ClientCertificateDelegate> delegate);
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // Add host and cert_path to map.
+  // When we get the "Certificate Request" packet from server,
+  // We find the matched cert path to host in the map.
+  virtual void AddDynamicCertificatePath(const std::string& host,
+                                         const std::string& cert_path) {}
+#endif
+
   // Returns a class to get notifications about media event. The embedder can
   // return nullptr if they're not interested.
   virtual MediaObserver* GetMediaObserver();
index de2662a..55e3323 100644 (file)
@@ -1304,6 +1304,11 @@ class WebContents : public PageNavigator,
   // user activation work.
   virtual bool HasRecentInteractiveInputEvent() = 0;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  virtual void AddDynamicCertificatePath(const std::string& host,
+                                         const std::string& cert_path) = 0;
+#endif
+
   // Sets a flag that causes the WebContents to ignore input events.
   virtual void SetIgnoreInputEvents(bool ignore_input_events) = 0;
 
index 98c1098..a40b601 100644 (file)
@@ -10,6 +10,9 @@
 #include <utility>
 
 #include "base/check_op.h"
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "base/logging.h"
+#endif
 #include "crypto/openssl_util.h"
 #include "third_party/boringssl/src/include/openssl/bn.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
@@ -18,7 +21,9 @@
 #include "third_party/boringssl/src/include/openssl/evp.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
 #include "third_party/boringssl/src/include/openssl/pkcs8.h"
-
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "third_party/boringssl/src/include/openssl/pem.h"
+#endif
 namespace crypto {
 
 ECPrivateKey::~ECPrivateKey() = default;
@@ -166,4 +171,45 @@ bool ECPrivateKey::ExportRawPublicKey(std::string* output) const {
 
 ECPrivateKey::ECPrivateKey() = default;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+bool ECPrivateKey::ConvertPEMtoDERFromPrivateKey(const std::string& key_buffer,
+                                                 std::vector<uint8_t>* output) {
+  bssl::UniquePtr<BIO> in(
+      BIO_new_mem_buf(const_cast<char*>(key_buffer.data()), key_buffer.size()));
+  if (!in) {
+    LOG(ERROR) << "Can't create a memory BIO";
+    return false;
+  }
+
+  bssl::UniquePtr<BIO> out(BIO_new(BIO_s_mem()));
+  if (!out) {
+    LOG(ERROR) << "BIO_new for converting a format of private key failed";
+    return false;
+  }
+
+  EVP_PKEY* pkey = PEM_read_bio_PrivateKey(in.get(), NULL, NULL, NULL);
+  if (!pkey) {
+    LOG(ERROR) << "Can't load private key";
+    return false;
+  }
+
+  int ret = i2d_PKCS8PrivateKeyInfo_bio(out.get(), pkey);
+  EVP_PKEY_free(pkey);
+  if (!ret) {
+    LOG(ERROR) << "Can't convert a format of private key";
+    return false;
+  }
+
+  char* data = nullptr;
+  long len = BIO_get_mem_data(out.get(), &data);
+
+  if (!data || len < 0) {
+    LOG(ERROR) << "Can't get der data from BIO";
+    return false;
+  }
+
+  output->assign(data, data + len);
+  return true;
+}
+#endif
 }  // namespace crypto
index bc0468d..500bfb7 100644 (file)
@@ -74,6 +74,10 @@ class CRYPTO_EXPORT ECPrivateKey {
   // Exports the public key as an EC point in X9.62 uncompressed form. Note this
   // includes the leading 0x04 byte.
   bool ExportRawPublicKey(std::string* output) const;
+#if BUILDFLAG(IS_TIZEN_TV)
+  static bool ConvertPEMtoDERFromPrivateKey(const std::string& key_buffer,
+                                            std::vector<uint8_t>* output);
+#endif
 
  private:
   // Constructor is private. Use one of the Create*() methods above instead.
index 2d63299..8ea7bc0 100644 (file)
@@ -4,6 +4,9 @@
 
 #include "net/cert/cert_database.h"
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "base/logging.h"
+#endif
 #include "base/memory/singleton.h"
 #include "base/observer_list_threadsafe.h"
 #include "build/build_config.h"
 #include "net/cert/x509_util_nss.h"
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "crypto/ec_private_key.h"
+#include "net/cert/x509_certificate.h"
+#endif
 namespace net {
 
 // static
@@ -76,6 +83,83 @@ int CertDatabase::ImportCACert(CERTCertificate* cert) {
 }
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+int CertDatabase::CheckUserCert(CERTCertificate* cert_obj) {
+  if (!cert_obj)
+    return ERR_CERT_INVALID;
+  // Check if the private key corresponding to the certificate exist
+  // We shouldn't accept any random client certificate sent by a CA.
+  // Note: The NSS source documentation wrongly suggests that this
+  // also imports the certificate if the private key exists. This
+  // doesn't seem to be the case.
+  PK11SlotInfo* slot = PK11_KeyForCertExists(cert_obj, NULL, NULL);
+  if (!slot)
+    return ERR_NO_PRIVATE_KEY_FOR_CERT;
+  PK11_FreeSlot(slot);
+  return OK;
+}
+
+int CertDatabase::AddUserCert(CERTCertificate* cert_obj) {
+  if (!cert_obj)
+    return ERR_CERT_INVALID;
+
+  CK_OBJECT_HANDLE key;
+  crypto::ScopedPK11Slot slot(PK11_KeyForCertExists(cert_obj, &key, NULL));
+  if (!slot.get())
+    return ERR_NO_PRIVATE_KEY_FOR_CERT;
+
+  std::string nickname =
+      x509_util::GetDefaultUniqueNickname(cert_obj, USER_CERT, slot.get());
+
+  // If an user cert was already imported in db,
+  // some error was occured in a second attempt to import that user cert.
+  // User cert that already imported doesn't need to import every time
+  // because a db is reused.
+  if (cert_obj->isperm) {
+    LOG(INFO) << "User cert already exists ("
+              << PK11_GetSlotName(cert_obj->slot) << "): \"" << nickname
+              << "\"";
+    return OK;
+  }
+
+  SECStatus result_value =
+      PK11_ImportCert(slot.get(), cert_obj, key, nickname.c_str(), PR_FALSE);
+  if (result_value != SECSuccess) {
+    LOG(ERROR) << "Couldn't import user certificate. " << PORT_GetError();
+    return ERR_ADD_USER_CERT_FAILED;
+  }
+  NotifyObserversCertDBChanged();
+  return OK;
+}
+
+bool CertDatabase::ImportPrivateKey(const std::string& key_buffer) {
+  std::vector<uint8> output;
+  if (!crypto::ECPrivateKey::ConvertPEMtoDERFromPrivateKey(key_buffer,
+                                                           &output)) {
+    LOG(ERROR) << "Private Key Convert fail";
+    return false;
+  }
+
+  SECItem der_private_key_info;
+  SECStatus result_value;
+  PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+
+  der_private_key_info.data = output.data();
+  der_private_key_info.len = output.size();
+
+  result_value = PK11_ImportDERPrivateKeyInfo(
+      slot, &der_private_key_info, NULL, NULL, PR_TRUE, PR_TRUE, KU_ALL, NULL);
+
+  if (result_value != SECSuccess) {
+    LOG(ERROR) << "Couldn't import Private Key. " << PORT_GetError();
+    return false;
+  }
+
+  LOG(INFO) << "Imported Private Key";
+  return true;
+}
+#endif
+
 void CertDatabase::AddObserver(Observer* observer) {
   observer_list_->AddObserver(observer);
 }
index 1fe4785..8e3d125 100644 (file)
 typedef struct CERTCertificateStr CERTCertificate;
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "base/files/file_util.h"
+#include "net/cert/x509_certificate.h"
+#endif
+
 namespace base {
 template <typename T> struct DefaultSingletonTraits;
 
@@ -95,6 +100,21 @@ class NET_EXPORT CertDatabase {
   // notifications from other DB interfaces.
   void NotifyObserversCertDBChanged();
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // Check whether this is a valid user cert that we have the private key for.
+  // Returns OK or a network error code such as ERR_CERT_CONTAINS_ERRORS.
+  int CheckUserCert(CERTCertificate* cert);
+
+  // Store user (client) certificate. Assumes CheckUserCert has already passed.
+  // Returns OK, or ERR_ADD_USER_CERT_FAILED if there was a problem saving to
+  // the platform cert database, or possibly other network error codes.
+  int AddUserCert(CERTCertificate* cert);
+
+  // Store Private Key to support mutual authentication.
+  // Returns OK if successful, or False if there was a problem.
+  bool ImportPrivateKey(const std::string& key_buffer);
+#endif
+
  private:
   friend struct base::DefaultSingletonTraits<CertDatabase>;
 
index 34548a0..94ca772 100644 (file)
@@ -85,7 +85,7 @@ external_content_browser_efl_sources = [
   "//tizen_src/chromium_impl/content/browser/input_picker/input_picker_base.h",
   "//tizen_src/chromium_impl/content/browser/javascript_dialog/javascript_modal_dialog.cc",
   "//tizen_src/chromium_impl/content/browser/javascript_dialog/javascript_modal_dialog.h",
-  "//tizen_src/chromium_impl/content/browser/public/browser/web_contents_efl_delegate.h",
+
   "//tizen_src/chromium_impl/content/browser/renderer_host/edge_effect.cc",
   "//tizen_src/chromium_impl/content/browser/renderer_host/edge_effect.h",
   "//tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc",
@@ -122,6 +122,10 @@ external_content_browser_efl_sources = [
   "//tizen_src/chromium_impl/content/browser/web_contents/web_drag_source_efl.h",
   "//tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc",
   "//tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h",
+  "//tizen_src/chromium_impl/content/public/browser/certificates_utils.cc",
+  "//tizen_src/chromium_impl/content/public/browser/certificates_utils.h",
+  "//tizen_src/chromium_impl/content/public/browser/web_contents_efl_delegate.h",
+  "//tizen_src/chromium_impl/content/public/browser/web_contents_view_efl_delegate.h",
 ]
 
 external_content_browser_efl_sources += [
diff --git a/tizen_src/chromium_impl/content/public/browser/certificates_utils.cc b/tizen_src/chromium_impl/content/public/browser/certificates_utils.cc
new file mode 100644 (file)
index 0000000..230f90f
--- /dev/null
@@ -0,0 +1,337 @@
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "certificates_utils.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "net/base/net_errors.h"
+#include "net/cert/cert_database.h"
+#include "net/cert/x509_util_nss.h"
+
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <fstream>
+#include "base/command_line.h"
+#include "chromium_impl/build/tizen_version.h"
+#include "content/public/browser/content_browser_client.h"
+#include "crypto/nss_crypto_module_delegate.h"
+#include "ewk/efl_integration/common/content_switches_efl.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_platform_key_nss.h"
+#include "net/ssl/ssl_private_key.h"
+#include "tizen_src/chromium_impl/tizen/vconf_handle.h"
+#include "web_product/web_product_tv.h"
+#endif
+
+namespace {
+#if BUILDFLAG(IS_TIZEN_TV)
+#if TIZEN_VERSION_EQ(5, 5, 0)  // Tizen 5.5
+const char* kDefaultCertPublic = "/usr/share/cert/SamsungDeviceCertificate.pem";
+#elif TIZEN_VERSION_EQ(6, 0, 0)  // Tizen 6.0
+const char* kDefaultCertPublic =
+    "/usr/share/sdp/pepper-key/SamsungDeviceCertificate.pem";
+#else
+const char* kDefaultCertPublic =
+    "/usr/share/sdp/psa-init-key/SamsungDeviceCertificate.pem";
+#endif
+const char* kDefaultCertPrivate = "SamsungDeviceCertificateKey.pem";
+const char* kICSAppId = "org.tizen.ics";  // ATSC 3.0
+const char* kICSDataName = "modelcert";
+const char* kICSTestDataName = "modelcert_test";
+const char* kICSTestUrl = "eurofins-digitaltesting.com";
+const char* kIntegratedCertPath = "/opt/data/cert/vdca.pem";
+const char* kWebSDIPublicKeyDataName = "CFL";
+const char* kWebSDIPrivateKeyDataName = "PFL";
+const char* VCONFKEY_CERT_VERSION = "db/certificate/version";
+std::unordered_map<std::string, std::string> dynamic_cert_map;
+#endif
+
+net::ScopedCERTCertificateList GetCertListFromFile(
+    const base::FilePath& file_path) {
+  std::string cert_data;
+  net::ScopedCERTCertificateList cert_list;
+  if (base::ReadFileToString(file_path, &cert_data)) {
+    cert_list = net::x509_util::CreateCERTCertificateListFromBytes(
+        cert_data.data(), cert_data.size(), net::X509Certificate::FORMAT_AUTO);
+  } else {
+    LOG(ERROR) << "Could not read file \"" << file_path.AsUTF8Unsafe()
+               << "\" for loading CA certs. Please check permissions!";
+  }
+  return cert_list;
+}
+
+#if BUILDFLAG(IS_TIZEN_TV)
+std::string ParseCertVersion(std::string ca_file) {
+  std::ifstream ca_file_(ca_file);
+  std::string ca_file_info;
+  std::getline(ca_file_, ca_file_info);
+  std::vector<std::string> version_str = base::SplitString(
+      ca_file_info, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  return version_str.size() > 2 ? version_str[2] : std::string();
+}
+
+bool IsLoadedCert(std::string old_cert_version, std::string new_cert_version) {
+  return base::EqualsCaseInsensitiveASCII(old_cert_version, new_cert_version);
+}
+
+bool CheckIfIntegratedCert(std::string ca_file_path) {
+  return ca_file_path == kIntegratedCertPath;
+}
+
+scoped_refptr<net::X509Certificate> MakeDynamicClientCert(
+    const std::string& host) {
+  auto iter = dynamic_cert_map.find(host);
+
+  LOG(INFO) << "[Dynamic Cert] host : " << host;
+  if (iter == dynamic_cert_map.end())
+    return nullptr;
+
+  LOG(INFO) << "[Dynamic Cert] matched cert key path or data name for"
+               " secure storage: "
+            << iter->second;
+  scoped_refptr<net::X509Certificate> client_cert;
+  if (client_cert = MakeClientCertFromSecureStorage(iter->second, iter->second))
+    return client_cert;
+
+  LOG(INFO) << "[Dynamic Cert] Try to get cert and key from file system";
+  base::FilePath dynamic_cert_path(iter->second);
+  std::string dynamic_cert_buffer;
+  if (!base::ReadFileToString(dynamic_cert_path, &dynamic_cert_buffer)) {
+    LOG(ERROR) << "[Dynamic Cert] Could not read file \"" << iter->second
+               << "\" for parsing client cert list. Please check permissions!";
+    return nullptr;
+  }
+  if (!dynamic_cert_buffer.empty()) {
+    client_cert = ImportKeyAndCreateClientCertChain(
+        std::string(), std::string(), dynamic_cert_buffer, dynamic_cert_buffer);
+  }
+  return client_cert;
+}
+#endif
+
+}  // namespace
+
+#if BUILDFLAG(IS_TIZEN_TV)
+scoped_refptr<net::X509Certificate> ImportKeyAndCreateClientCertChain(
+    std::string cert_file,
+    std::string key_file,
+    std::string cert_buffer,
+    const std::string& key_buffer) {
+  net::ScopedCERTCertificateList public_cert_list;
+  if (!net::CertDatabase::GetInstance()->ImportPrivateKey(key_buffer)) {
+    LOG(ERROR) << "Private Key could not be added \"" << key_file << "\"";
+    return nullptr;
+  }
+
+  if (cert_buffer.empty()) {
+    LOG(INFO) << "Public Key from Secure Storage is NULL, "
+                 "Get it in File like previous way.";
+    base::FilePath public_file_path(cert_file);
+    if (!base::ReadFileToString(public_file_path, &cert_buffer)) {
+      LOG(ERROR)
+          << "Could not read file \"" << public_file_path.AsUTF8Unsafe()
+          << "\" for parsing client cert list. Please check permissions!";
+      return nullptr;
+    }
+  }
+
+  public_cert_list = net::x509_util::CreateCERTCertificateListFromBytes(
+      cert_buffer.data(), cert_buffer.size(),
+      net::X509Certificate::FORMAT_AUTO);
+
+  std::vector<std::string> certificates;
+  for (const auto& cert : public_cert_list) {
+    std::string der_encoded_cert;
+    if (!net::x509_util::GetDEREncoded(cert.get(), &der_encoded_cert)) {
+      return nullptr;
+    }
+    certificates.push_back(der_encoded_cert);
+  }
+
+  std::vector<base::StringPiece> cert_pieces(certificates.size());
+  for (unsigned i = 0; i < certificates.size(); i++) {
+    cert_pieces[i] = base::StringPiece(certificates[i]);
+  }
+
+  return net::X509Certificate::CreateFromDERCertChain(cert_pieces);
+}
+
+scoped_refptr<net::X509Certificate> MakeClientCertFromSecureStorage(
+    std::string cert_file,
+    std::string key_file) {
+  std::string cert_buffer;
+  std::string key_buffer;
+
+  wp_tv_create();
+  Wp_Bool ret = wp_tv_create_feature(FEATURE_SECURITY);
+  if (ret) {
+    cert_buffer = wp_tv_get_key_from_secure_storage(cert_file);
+    key_buffer = wp_tv_get_key_from_secure_storage(key_file);
+  } else {
+    LOG(ERROR) << "wp_tv_create_feature fail";
+  }
+  wp_tv_destroy_feature(FEATURE_SECURITY);
+
+  if (key_buffer.empty()) {
+    LOG(ERROR) << "Private Key from Secure Storage is NULL. \"" << key_file
+               << "\"";
+    return nullptr;
+  }
+
+  return ImportKeyAndCreateClientCertChain(cert_file, key_file, cert_buffer,
+                                           key_buffer);
+}
+
+void AddDynamicClientCertificate(const std::string& host,
+                                 const std::string& certificate_path) {
+  LOG(ERROR) << "Add dynamic client certificate, host = " << host
+             << ", certificate_path = " << certificate_path;
+  dynamic_cert_map[host] = certificate_path;
+}
+
+scoped_refptr<net::SSLPrivateKey> GetPrivateKey(
+    scoped_refptr<net::X509Certificate> client_cert) {
+  if (!client_cert)
+    return nullptr;
+
+  auto nss_cert = net::x509_util::CreateCERTCertificateFromX509Certificate(
+      client_cert.get());
+  if (!nss_cert)
+    return nullptr;
+
+  auto cert_db = net::CertDatabase::GetInstance();
+  int err_code = cert_db->CheckUserCert(nss_cert.get());
+  if (net::OK != err_code) {
+    LOG(ERROR) << "User certificate is not valid. Error code : " << err_code;
+    return nullptr;
+  }
+
+  err_code = cert_db->AddUserCert(nss_cert.get());
+  if (net::OK != err_code) {
+    LOG(ERROR) << "User certificate could not be added. Error code : "
+               << err_code;
+    return nullptr;
+  }
+
+  return net::FetchClientCertPrivateKey(client_cert.get(), nss_cert.get(),
+                                        nullptr);
+}
+
+scoped_refptr<net::X509Certificate> GetClientCertificate(
+    bool enabled_websdi,
+    net::SSLCertRequestInfo* cert_request_info) {
+  scoped_refptr<net::X509Certificate> client_cert;
+  std::string host = cert_request_info->host_and_port.host();
+  std::string tizen_app_id =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kTizenAppId);
+
+  LOG(INFO) << "[Client Authentication] SelectClientCertificate, WEBSDI = "
+            << enabled_websdi << ", app ID : " << tizen_app_id;
+  client_cert = MakeDynamicClientCert(host);
+  if (!client_cert && enabled_websdi) {
+    LOG(INFO) << "[Client Authentication] Get a Client Cert for WebSDI";
+    client_cert = MakeClientCertFromSecureStorage(kWebSDIPublicKeyDataName,
+                                                  kWebSDIPrivateKeyDataName);
+  } else if (!client_cert && tizen_app_id == kICSAppId) {
+    LOG(INFO) << "[Client Authentication] Get a Client Cert for ICS";
+    std::string data_name;
+    if (host.find(kICSTestUrl) != std::string::npos)
+      data_name = kICSTestDataName;
+    else
+      data_name = kICSDataName;
+
+    client_cert = MakeClientCertFromSecureStorage(data_name, data_name);
+  }
+
+  if (!client_cert) {
+    LOG(INFO) << "[Default Cert] Try to Load Default Client Certificate";
+    client_cert = MakeClientCertFromSecureStorage(kDefaultCertPublic,
+                                                  kDefaultCertPrivate);
+  }
+
+  if (!client_cert) {
+    LOG(ERROR) << "[Client Authentication] client_cert is null, "
+                  "Client Authentication will be failed";
+    return nullptr;
+  }
+
+  if (client_cert->HasExpired()) {
+    LOG(ERROR)
+        << "[Client Authentication] client_cert error: ERR_CERT_DATE_INVALID, "
+           "Client Authentication will be failed";
+    return nullptr;
+  }
+  return client_cert;
+}
+
+#endif  // BUILDFLAG(IS_TIZEN_TV)
+
+void AddServerCert(const std::string& certificate_path) {
+  std::string ca_file_path = certificate_path;
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (certificate_path.empty())
+    ca_file_path = kIntegratedCertPath;
+
+  base::FilePath cert_file_path(ca_file_path);
+  if (!base::PathExists(cert_file_path))
+    return;
+
+  std::string cert_version = VconfHandle(VCONFKEY_CERT_VERSION).Str();
+  std::string old_cert_version;
+  if (!cert_version.empty()) {
+    old_cert_version = cert_version;
+  }
+
+  bool isintegratedCert = false;
+  std::string new_cert_version;
+#endif
+
+  std::vector<std::string> paths = base::SplitString(
+      ca_file_path, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  for (const auto& path : paths) {
+#if BUILDFLAG(IS_TIZEN_TV)
+    if ((isintegratedCert = CheckIfIntegratedCert(path)) == true) {
+      new_cert_version = ParseCertVersion(path);
+      if (IsLoadedCert(old_cert_version, new_cert_version)) {
+        LOG(INFO) << "skip loading certificates because it is already loaded";
+        continue;
+      }
+    }
+#endif
+    base::FilePath file_path(path);
+    base::File file(file_path, base::File::FLAG_OPEN);
+    base::File::Info file_info;
+    // Check if path is accessible
+    if (file.IsValid() && file.GetInfo(&file_info)) {
+      if (file_info.is_directory) {
+        base::FileEnumerator files(
+            file_path, true,
+            base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS,
+            "@(*.crt|*.pem)");
+        files.SetExtMatchToFlag();
+        for (base::FilePath cert_file = files.Next(); !cert_file.empty();
+             cert_file = files.Next()) {
+          for (const auto& ca_cert : GetCertListFromFile(cert_file)) {
+            net::CertDatabase::GetInstance()->ImportCACert(ca_cert.get());
+          }
+        }
+      } else {
+        for (const auto& ca_cert : GetCertListFromFile(file_path)) {
+          net::CertDatabase::GetInstance()->ImportCACert(ca_cert.get());
+        }
+      }
+#if BUILDFLAG(IS_TIZEN_TV)
+      if (isintegratedCert)
+        VconfHandle(VCONFKEY_CERT_VERSION).Set(new_cert_version);
+#endif
+    } else {  // Stat returned non-zero, path not accesible
+      LOG(ERROR) << "Could not access path \"" << path
+                 << "\" for loading CA certs. Please check permissions!";
+    }
+  }
+}
diff --git a/tizen_src/chromium_impl/content/public/browser/certificates_utils.h b/tizen_src/chromium_impl/content/public/browser/certificates_utils.h
new file mode 100644 (file)
index 0000000..04245bf
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CERTIFICATES_UTILS_H_
+#define CERTIFICATES_UTILS_H_
+#include <string>
+#include "build/build_config.h"
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "base/memory/scoped_refptr.h"
+
+namespace net {
+class SSLCertRequestInfo;
+class SSLPrivateKey;
+class X509Certificate;
+}  // namespace net
+
+scoped_refptr<net::X509Certificate> ImportKeyAndCreateClientCertChain(
+    std::string cert_file,
+    std::string key_file,
+    std::string cert_buffer,
+    const std::string& key_buffer);
+scoped_refptr<net::X509Certificate> MakeClientCertFromSecureStorage(
+    std::string cert_file,
+    std::string key_file);
+void AddDynamicClientCertificate(const std::string& host,
+                                 const std::string& certificate_path);
+scoped_refptr<net::SSLPrivateKey> GetPrivateKey(
+    scoped_refptr<net::X509Certificate> client_cert);
+scoped_refptr<net::X509Certificate> GetClientCertificate(
+    bool enabled_websdi,
+    net::SSLCertRequestInfo* cert_request_info);
+#endif
+
+void AddServerCert(const std::string& certificate_path);
+
+#endif  // CERTIFICATES_UTILS_H_
index b71db9f..67dcfee 100644 (file)
@@ -79,6 +79,9 @@ shared_library("chromium-ewk") {
   public_configs += [ "//tizen_src/build:ui-gadget-public" ]
   configs += [ "//tizen_src/build:notification" ]
   configs += [ "//tizen_src/build:libnotification" ]
+  if(tizen_product_tv) {
+    configs += [ "//tizen_src/build:WebProduct" ]
+  }
   deps = [
     "//base/:base_static",
     "//components/autofill/content/browser",
index 4df6dcc..d0d4961 100644 (file)
@@ -36,6 +36,7 @@
 #include "net/cert/x509_util_nss.h"
 #include "network_delegate_efl.h"
 #include "permission_controller_delegate_efl.h"
+#include "tizen_src/chromium_impl/content/public/browser/certificates_utils.h"
 
 #if BUILDFLAG(IS_TIZEN_TV)
 #include "content/common/zygote/zygote_communication_linux.h"
@@ -54,19 +55,6 @@ void HandleReadError(PersistentPrefStore::PrefReadError error) {
   NOTIMPLEMENTED();
 }
 
-net::ScopedCERTCertificateList GetCertListFromFile(
-    const base::FilePath& file_path) {
-  std::string cert_data;
-  net::ScopedCERTCertificateList cert_list;
-  if (base::ReadFileToString(file_path, &cert_data)) {
-    cert_list = net::x509_util::CreateCERTCertificateListFromBytes(
-        cert_data.data(), cert_data.size(), net::X509Certificate::FORMAT_AUTO);
-  } else {
-    LOG(ERROR) << "Could not read file \"" << file_path.AsUTF8Unsafe()
-               << "\" for loading CA certs. Please check permissions!";
-  }
-  return cert_list;
-}
 
 void SendToAllRenderers(IPC::Message* message) {
   content::RenderProcessHost::iterator it =
@@ -316,43 +304,7 @@ void BrowserContextEfl::SetCertificatePath(
     return;
 
   file_system_context->default_file_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&BrowserContextEfl::ReadCertificateAndAdd,
-                     base::Owned(new std::string(certificate_path))));
-}
-
-void BrowserContextEfl::ReadCertificateAndAdd(
-    const std::string* certificate_path) {
-  std::vector<std::string> paths = base::SplitString(
-      *certificate_path, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  for (const auto& path : paths) {
-    base::FilePath file_path(path);
-    base::File file(file_path, base::File::FLAG_OPEN);
-    base::File::Info file_info;
-    // Check if path is accessible
-    if (file.IsValid() && file.GetInfo(&file_info)) {
-      if (file_info.is_directory) {
-        base::FileEnumerator files(
-            file_path, true,
-            base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS,
-            "@(*.crt|*.pem)");
-        files.SetExtMatchToFlag();
-        for (base::FilePath cert_file = files.Next(); !cert_file.empty();
-             cert_file = files.Next()) {
-          for (const auto& ca_cert : GetCertListFromFile(cert_file)) {
-            net::CertDatabase::GetInstance()->ImportCACert(ca_cert.get());
-          }
-        }
-      } else {
-        for (const auto& ca_cert : GetCertListFromFile(file_path)) {
-          net::CertDatabase::GetInstance()->ImportCACert(ca_cert.get());
-        }
-      }
-    } else {  // Stat returned non-zero, path not accessible
-      LOG(ERROR) << "Could not access path \"" << path
-                 << "\" for loading CA certs. Please check permissions!";
-    }
-  }
+      FROM_HERE, base::BindOnce(&AddServerCert, certificate_path));
 }
 
 void BrowserContextEfl::InitVisitedLinkWriter() {
index f87cf20..43e4254 100644 (file)
@@ -147,10 +147,6 @@ class BrowserContextEfl : public BrowserContext,
 #endif
 
  private:
-  // certificate_path should be either be a directory with CA certs, a CA cert
-  // file or a colon-separated list of those. CA cert files should have *.crt
-  // extension. Directories are traversed recursively.
-  static void ReadCertificateAndAdd(const std::string* certificate_path);
   SSLHostStateDelegate* GetSSLHostStateDelegate() override;
   PermissionControllerDelegate* GetPermissionControllerDelegate() override;
   mutable std::unique_ptr<GeolocationPermissionContextEfl>
index 5f72ea0..458d050 100644 (file)
@@ -63,6 +63,9 @@
 
 #if BUILDFLAG(IS_TIZEN_TV)
 #include "wrt/hbbtv_widget_host.h"
+#include "content/public/browser/client_certificate_delegate.h"
+#include "tizen_src/chromium_impl/content/public/browser/certificates_utils.h"
+#include "web_product_tv.h"
 #endif
 
 using web_contents_utils::WebContentsFromFrameID;
@@ -256,7 +259,12 @@ void AcceptLanguagesHelper::NotifyAcceptLangsChanged() {
 
 ContentBrowserClientEfl::ContentBrowserClientEfl()
     : notification_controller_(new NotificationControllerEfl),
-      accept_langs_helper_(new AcceptLanguagesHelper) {
+      accept_langs_helper_(new AcceptLanguagesHelper)
+#if BUILDFLAG(IS_TIZEN_TV)
+      ,
+      enabled_websdi_(false)
+#endif
+{
 #if BUILDFLAG(IS_TIZEN)
   PlatformLanguageChanged(nullptr, this);
   vconf_notify_key_changed(VCONFKEY_LANGSET, PlatformLanguageChanged, this);
@@ -264,6 +272,9 @@ ContentBrowserClientEfl::ContentBrowserClientEfl()
 }
 
 ContentBrowserClientEfl::~ContentBrowserClientEfl() {
+#if BUILDFLAG(IS_TIZEN_TV)
+  wp_tv_destroy_feature(FEATURE_SECURITY);
+#endif
 #if BUILDFLAG(IS_TIZEN)
   vconf_ignore_key_changed(VCONFKEY_LANGSET, PlatformLanguageChanged);
 #endif
@@ -629,4 +640,34 @@ ContentBrowserClientEfl::CreateURLLoaderThrottles(
   return result;
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+base::OnceClosure ContentBrowserClientEfl::SelectClientCertificate(
+    WebContents* web_contents,
+    net::SSLCertRequestInfo* cert_request_info,
+    net::ClientCertIdentityList client_certs,
+    std::unique_ptr<ClientCertificateDelegate> delegate) {
+  scoped_refptr<net::X509Certificate> client_cert;
+  scoped_refptr<net::SSLPrivateKey> private_key;
+
+  const EWebContext* const context =
+      static_cast<BrowserContextEfl*>(web_contents->GetBrowserContext())
+          ->WebContext();
+
+  client_cert = GetClientCertificate(enabled_websdi_, cert_request_info);
+  if (client_cert) {
+    private_key = GetPrivateKey(client_cert);
+    delegate->ContinueWithCertificate(std::move(client_cert),
+                                      std::move(private_key));
+  }
+
+  return base::OnceClosure();
+}
+
+void ContentBrowserClientEfl::AddDynamicCertificatePath(
+    const std::string& host,
+    const std::string& cert_path) {
+  AddDynamicClientCertificate(host, cert_path);
+}
+#endif
+
 }  // namespace content
index 534ea91..286c737 100644 (file)
@@ -159,6 +159,18 @@ class ContentBrowserClientEfl : public ContentBrowserClient {
   std::string GetAcceptLangs(BrowserContext* context) override;
 
   void EnableAppControl(bool enabled) { enabled_app_control = enabled; }
+#if BUILDFLAG(IS_TIZEN_TV)
+  void AddDynamicCertificatePath(const std::string& host,
+                                 const std::string& cert_path) override;
+  base::OnceClosure SelectClientCertificate(
+      WebContents* web_contents,
+      net::SSLCertRequestInfo* cert_request_info,
+      net::ClientCertIdentityList client_certs,
+      std::unique_ptr<ClientCertificateDelegate> delegate) override;
+
+  void SetWebSDI(bool enable) { enabled_websdi_ = enable; }
+  bool GetWebSDI() const { return enabled_websdi_; }
+#endif
 
  private:
   bool WillCreateURLLoaderFactory(
@@ -187,6 +199,9 @@ class ContentBrowserClientEfl : public ContentBrowserClient {
   scoped_refptr<SharedURLLoaderFactoryEfl> shared_url_loader_factory_;
 
   std::unique_ptr<AcceptLanguagesHelper> accept_langs_helper_;
+#if BUILDFLAG(IS_TIZEN_TV)
+  bool enabled_websdi_;
+#endif
   bool shutting_down_ = false;
   bool enabled_app_control = true;
 };
index c9ad53b..bb7c4a0 100644 (file)
@@ -3264,6 +3264,13 @@ bool EWebView::ShouldIgnoreNavigation(
   return app_control.Proceed();
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void EWebView::AddDynamicCertificatePath(const std::string& host,
+                                         const std::string& cert_path) {
+  web_contents_->AddDynamicCertificatePath(host, cert_path);
+}
+#endif
+
 bool EWebView::SetVisibility(bool enable) {
   if (!web_contents_)
     return false;
index f2a13e9..908b579 100644 (file)
@@ -720,6 +720,8 @@ class EWebView {
   void DrawLabel(Evas_Object* image, Eina_Rectangle rect);
   void DeactivateAtk(bool deactivated);
   void ClearLabels();
+  void AddDynamicCertificatePath(const std::string& host,
+                                 const std::string& cert_path);
 #endif  // IS_TIZEN_TV
 
   void SetDidChangeThemeColorCallback(
index c66aadc..e48652a 100644 (file)
@@ -906,13 +906,26 @@ void ewk_context_register_jsplugin_mime_types(Ewk_Context* context, const Eina_L
 
 void ewk_context_websdi_set(Eina_Bool enable)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "This App use WebSDI for client authentication [" << enable << "]";
+  ContentBrowserClientEfl* cbce = GetContentBrowserClient();
+  EINA_SAFETY_ON_NULL_RETURN(cbce);
+  cbce->SetWebSDI(enable);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV");
+#endif
 }
 
 Eina_Bool ewk_context_websdi_get()
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  const ContentBrowserClientEfl* cbce = GetContentBrowserClient();
+  EINA_SAFETY_ON_NULL_RETURN_VAL(cbce, EINA_FALSE);
+  return cbce->GetWebSDI();
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV");
   return false;
+#endif
 }
 
 void ewk_context_disable_nosniff_set(Ewk_Context* context, Eina_Bool enable)
index 3acbbef..9be3dd6 100644 (file)
@@ -1376,7 +1376,12 @@ void ewk_view_mirrored_blur_set(Evas_Object* o, Eina_Bool state)
 
 void ewk_view_add_dynamic_certificate_path(const Evas_Object *ewkView, const char* host, const char* cert_path)
 {
+#if BUILDFLAG(IS_TIZEN_TV)
+  EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl);
+  impl->AddDynamicCertificatePath(std::string(host), std::string(cert_path));
+#else
   LOG_EWK_API_MOCKUP();
+#endif
 }
 
 void ewk_view_atk_deactivation_by_app(Evas_Object* view, Eina_Bool enable)