Bug 1937808 - Export OSClientCerts in libxul instead of shared library r=keeler,glandium

Differential Revision: https://phabricator.services.mozilla.com/D230412
This commit is contained in:
Anna Weine
2025-01-15 19:46:29 +00:00
parent 5e051b9062
commit d010e93c00
20 changed files with 128 additions and 178 deletions

5
Cargo.lock generated
View File

@@ -2457,6 +2457,7 @@ dependencies = [
"nsstring",
"oblivious_http",
"origin-trials-ffi",
"osclientcerts",
"oxilangtag",
"oxilangtag-ffi",
"prefs_parser",
@@ -4839,7 +4840,7 @@ dependencies = [
]
[[package]]
name = "osclientcerts-static"
name = "osclientcerts"
version = "0.1.4"
dependencies = [
"byteorder",
@@ -4848,10 +4849,10 @@ dependencies = [
"lazy_static",
"libloading",
"log",
"mozilla-central-workspace-hack",
"pkcs11-bindings",
"rsclientcerts",
"sha2",
"static_prefs",
"winapi",
]

View File

@@ -359,14 +359,6 @@ bin/libfreebl_64int_3.so
@RESPATH@/chrome/pippki@JAREXT@
@RESPATH@/chrome/pippki.manifest
; preprocessor.py doesn't handle parentheses, so while the following could be
; expressed in a single line, it's more clear to break them up.
#if defined(XP_WIN) || defined(XP_MACOSX)
#if !defined(_ARM64_)
@BINPATH@/@DLL_PREFIX@osclientcerts@DLL_SUFFIX@
#endif
#endif
@BINPATH@/@DLL_PREFIX@ipcclientcerts@DLL_SUFFIX@
; For process sandboxing

View File

@@ -274,5 +274,4 @@ jsrust = ["dep:allocator-api2", "dep:arrayvec", "dep:byteorder", "dep:cc", "dep:
minidump-analyzer-export = ["dep:allocator-api2", "dep:arrayvec", "dep:bitflags", "dep:byteorder", "dep:clap", "dep:env_logger", "dep:futures-channel", "dep:futures-core", "dep:futures-executor", "dep:futures-sink", "dep:futures-util", "dep:getrandom", "dep:hashbrown", "dep:hex", "dep:indexmap", "dep:log", "dep:memchr", "dep:nom", "dep:num-traits", "dep:object", "dep:once_cell", "dep:scroll", "dep:serde_json", "dep:time", "dep:time-macros", "dep:tracing", "dep:uuid", "dep:windows-sys", "dep:zerocopy"]
mozwer_s = ["dep:allocator-api2", "dep:byteorder", "dep:getrandom", "dep:hashbrown", "dep:indexmap", "dep:log", "dep:once_cell", "dep:scroll", "dep:serde_json", "dep:uuid", "dep:windows-sys", "dep:zerocopy"]
nmhproxy = ["dep:allocator-api2", "dep:bitflags", "dep:byteorder", "dep:form_urlencoded", "dep:hashbrown", "dep:icu_locid", "dep:icu_properties", "dep:idna", "dep:indexmap", "dep:once_cell", "dep:percent-encoding", "dep:serde_json", "dep:smallvec", "dep:stable_deref_trait", "dep:tinystr", "dep:unicode-bidi", "dep:url", "dep:windows-sys", "dep:yoke", "dep:zerocopy", "dep:zerofrom", "dep:zerovec"]
osclientcerts-static = ["dep:bindgen", "dep:bitflags", "dep:byteorder", "dep:core-foundation-sys", "dep:env_logger", "dep:itertools", "dep:log", "dep:memchr", "dep:nom", "dep:regex"]
test-builtins-static = ["dep:bindgen", "dep:bitflags", "dep:itertools", "dep:memchr", "dep:nom", "dep:regex", "dep:smallvec"]

View File

@@ -16094,6 +16094,7 @@
type: RelaxedAtomicBool
value: true
mirror: always
rust: true
- name: security.pki.cert_short_lifetime_in_days
type: RelaxedAtomicUint32

View File

@@ -1789,6 +1789,27 @@ bool LoadUserModuleAt(const char* moduleName, const char* libraryName,
return true;
}
bool LoadUserModuleFromXul(const char* moduleName,
CK_C_GetFunctionList fentry) {
// If a module exists with the same name, make a best effort attempt to delete
// it. Note that it isn't possible to delete the internal module, so checking
// the return value would be detrimental in that case.
int unusedModType;
Unused << SECMOD_DeleteModule(moduleName, &unusedModType);
UniqueSECMODModule userModule(
SECMOD_LoadUserModuleWithFunction(moduleName, fentry));
if (!userModule) {
return false;
}
if (!userModule->loaded) {
return false;
}
return true;
}
bool LoadIPCClientCertsModule(const nsCString& dir) {
// The IPC client certs module needs to be able to call back into gecko to be
// able to communicate with the parent process over IPC. This is achieved by
@@ -1812,13 +1833,24 @@ bool LoadIPCClientCertsModule(const nsCString& dir) {
return true;
}
bool LoadOSClientCertsModule(const nsCString& dir) {
nsLiteralCString params =
StaticPrefs::security_osclientcerts_assume_rsa_pss_support()
? "RSA-PSS"_ns
: ""_ns;
return LoadUserModuleAt(kOSClientCertsModuleName.get(), "osclientcerts", dir,
params.get());
extern "C" {
// Extern function to call osclientcerts module C_GetFunctionList.
// NSS calls it to obtain the list of functions comprising this module.
// ppFunctionList must be a valid pointer.
CK_RV OSClientCerts_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
} // extern "C"
bool LoadOSClientCertsModule() {
// Corresponds to Rust cfg(any(
// target_os = "macos",
// target_os = "ios",
// all(target_os = "windows", not(target_arch = "aarch64"))))]
#if defined(__APPLE__) || (defined WIN32 && !defined(__aarch64__))
return LoadUserModuleFromXul(kOSClientCertsModuleName.get(),
OSClientCerts_C_GetFunctionList);
#else
return false;
#endif
}
bool LoadLoadableRoots(const nsCString& dir) {

View File

@@ -80,12 +80,9 @@ bool LoadLoadableRoots(const nsCString& dir);
/**
* Loads the OS client certs module.
*
* @param dir
* The path to the directory containing the module. This should be the
* same as where all of the other gecko libraries live.
* @return true if the module was successfully loaded, false otherwise.
*/
bool LoadOSClientCertsModule(const nsCString& dir);
bool LoadOSClientCertsModule();
/**
* Loads the IPC client certs module.

View File

@@ -4,14 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# osclientcerts is currently only implemented for Windows
# osclientcerts transitively depends on winapi 0.2.8, which doesn't work with
# AArch64
if (CONFIG["OS_ARCH"] == "WINNT" and CONFIG["TARGET_CPU"] != "aarch64") or CONFIG[
"OS_ARCH"
] == "Darwin":
DIRS += ["osclientcerts"]
DIRS += ["ipcclientcerts"]
DIRS += ["builtins"]
@@ -177,16 +169,11 @@ if CONFIG["TARGET_KERNEL"] == "Darwin":
"OSReauthenticatorDarwin.mm",
]
OS_LIBS += [
"-framework CoreFoundation",
"-framework LocalAuthentication",
"-framework Security",
]
if CONFIG["OS_ARCH"] == "WINNT":
OS_LIBS += ["credui"]
UNIFIED_SOURCES += [
"CredentialManagerSecret.cpp",
]
IPDL_SOURCES += [
"PIPCClientCerts.ipdl",
"PSelectTLSClientAuthCert.ipdl",
@@ -194,6 +181,31 @@ IPDL_SOURCES += [
"PVerifySSLServerCert.ipdl",
]
# Required by OSClientCerts and CredentialManagerSecret.
if CONFIG["OS_ARCH"] == "WINNT":
OS_LIBS += [
"advapi32",
"credui",
"crypt32",
"kernel32",
"ncrypt",
"userenv",
"ws2_32",
"ntdll",
]
UNIFIED_SOURCES += [
"CredentialManagerSecret.cpp",
]
# Version string comparison is generally wrong, but by the time it would
# actually matter, either bug 1489995 would be fixed, or the build would
# require version >= 1.78.
if CONFIG["RUSTC_VERSION"] and CONFIG["RUSTC_VERSION"] >= "1.78.0":
OS_LIBS += [
"synchronization",
]
FINAL_LIBRARY = "xul"
LOCAL_INCLUDES += [

View File

@@ -482,14 +482,12 @@ class LoadLoadableCertsTask final : public Runnable {
public:
LoadLoadableCertsTask(nsNSSComponent* nssComponent,
bool importEnterpriseRoots,
Vector<nsCString>&& possibleLoadableRootsLocations,
Maybe<nsCString>&& osClientCertsModuleLocation)
Vector<nsCString>&& possibleLoadableRootsLocations)
: Runnable("LoadLoadableCertsTask"),
mNSSComponent(nssComponent),
mImportEnterpriseRoots(importEnterpriseRoots),
mPossibleLoadableRootsLocations(
std::move(possibleLoadableRootsLocations)),
mOSClientCertsModuleLocation(std::move(osClientCertsModuleLocation)) {
std::move(possibleLoadableRootsLocations)) {
MOZ_ASSERT(nssComponent);
}
@@ -503,7 +501,6 @@ class LoadLoadableCertsTask final : public Runnable {
RefPtr<nsNSSComponent> mNSSComponent;
bool mImportEnterpriseRoots;
Vector<nsCString> mPossibleLoadableRootsLocations; // encoded in UTF-8
Maybe<nsCString> mOSClientCertsModuleLocation; // encoded in UTF-8
};
nsresult LoadLoadableCertsTask::Dispatch() {
@@ -545,12 +542,14 @@ LoadLoadableCertsTask::Run() {
mNSSComponent->ImportEnterpriseRoots();
mNSSComponent->UpdateCertVerifierWithEnterpriseRoots();
}
if (mOSClientCertsModuleLocation.isSome()) {
bool success = LoadOSClientCertsModule(*mOSClientCertsModuleLocation);
if (StaticPrefs::security_osclientcerts_autoload()) {
bool success = LoadOSClientCertsModule();
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("loading OS client certs module %s",
success ? "succeeded" : "failed"));
}
{
MonitorAutoLock rootsLoadedLock(mNSSComponent->mLoadableCertsLoadedMonitor);
mNSSComponent->mLoadableCertsLoaded = true;
@@ -590,12 +589,11 @@ static nsresult GetDirectoryPath(const char* directoryKey, nsCString& result) {
class BackgroundLoadOSClientCertsModuleTask final : public CryptoTask {
public:
explicit BackgroundLoadOSClientCertsModuleTask(const nsCString&& libraryDir)
: mLibraryDir(std::move(libraryDir)) {}
explicit BackgroundLoadOSClientCertsModuleTask() {}
private:
virtual nsresult CalculateResult() override {
bool success = LoadOSClientCertsModule(mLibraryDir);
bool success = LoadOSClientCertsModule();
return success ? NS_OK : NS_ERROR_FAILURE;
}
@@ -610,19 +608,12 @@ class BackgroundLoadOSClientCertsModuleTask final : public CryptoTask {
nullptr, "psm:load-os-client-certs-module-task-ran", nullptr);
}
}
nsCString mLibraryDir;
};
void AsyncLoadOrUnloadOSClientCertsModule(bool load) {
if (load) {
nsCString libraryDir;
nsresult rv = GetDirectoryPath(NS_GRE_BIN_DIR, libraryDir);
if (NS_FAILED(rv)) {
return;
}
RefPtr<BackgroundLoadOSClientCertsModuleTask> task =
new BackgroundLoadOSClientCertsModuleTask(std::move(libraryDir));
new BackgroundLoadOSClientCertsModuleTask();
Unused << task->Dispatch();
} else {
UniqueSECMODModule osClientCertsModule(
@@ -1660,19 +1651,9 @@ nsresult nsNSSComponent::InitializeNSS() {
return rv;
}
bool loadOSClientCertsModule =
StaticPrefs::security_osclientcerts_autoload();
Maybe<nsCString> maybeOSClientCertsModuleLocation;
if (loadOSClientCertsModule) {
nsAutoCString libraryDir;
if (NS_SUCCEEDED(GetDirectoryPath(NS_GRE_BIN_DIR, libraryDir))) {
maybeOSClientCertsModuleLocation.emplace(libraryDir);
}
}
RefPtr<LoadLoadableCertsTask> loadLoadableCertsTask(
new LoadLoadableCertsTask(this, importEnterpriseRoots,
std::move(possibleLoadableRootsLocations),
std::move(maybeOSClientCertsModuleLocation)));
std::move(possibleLoadableRootsLocations)));
rv = loadLoadableCertsTask->Dispatch();
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
if (NS_FAILED(rv)) {

View File

@@ -1,10 +1,9 @@
[package]
name = "osclientcerts-static"
name = "osclientcerts"
version = "0.1.4"
authors = ["Dana Keeler <dkeeler@mozilla.com>"]
edition = "2018"
description = "Platform-specific support for client authentication certificates in Firefox"
repository = "https://github.com/mozkeeler/osclientcerts"
license = "MPL-2.0"
[dependencies]
@@ -12,11 +11,11 @@ byteorder = "1.3"
env_logger = {version = "0.10", default-features = false } # disable `regex` to reduce code size
lazy_static = "1"
log = "0.4"
mozilla-central-workspace-hack = { version = "0.1", features = ["osclientcerts-static"], optional = true }
pkcs11-bindings = "0.1"
rsclientcerts = { path = "../rsclientcerts" }
sha2 = "0.10.2"
static_prefs = { path = "../../../../modules/libpref/init/static_prefs"}
[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.core-foundation]
version = "0.9"
@@ -27,6 +26,3 @@ version = "0.8"
[target."cfg(target_os = \"windows\")".dependencies.winapi]
version = "0.3"
features = ["errhandlingapi", "wincrypt"]
[lib]
crate-type = ["staticlib"]

View File

@@ -1,40 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
USE_LIBS += ["osclientcerts-static"]
UNIFIED_SOURCES += [
"stub.cpp",
]
if CONFIG["OS_ARCH"] == "WINNT":
OS_LIBS += [
"advapi32",
"crypt32",
"kernel32",
"ncrypt",
"userenv",
"ws2_32",
"ntdll",
]
# Version string comparison is generally wrong, but by the time it would
# actually matter, either bug 1489995 would be fixed, or the build would
# require version >= 1.78.
if CONFIG["RUSTC_VERSION"] and CONFIG["RUSTC_VERSION"] >= "1.78.0":
OS_LIBS += [
"synchronization",
]
if CONFIG["OS_ARCH"] == "Darwin":
OS_LIBS += [
"-framework CoreFoundation",
"-framework Security",
]
SharedLibrary("osclientcerts")
NoVisibilityFlags()
SYMBOLS_FILE = "osclientcerts.symbols"

View File

@@ -1,8 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is an intentionally empty file. It is necessary for the build system to
// successfully convert a static rust library into a dynamic library on
// Windows.

View File

@@ -1,9 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ["dynamic-library"]
RustLibrary("osclientcerts-static")

View File

@@ -21,23 +21,22 @@ extern crate pkcs11_bindings;
#[macro_use]
extern crate rsclientcerts;
extern crate sha2;
#[cfg(target_os = "windows")]
#[cfg(all(target_os = "windows", not(target_arch = "aarch64")))]
extern crate winapi;
use pkcs11_bindings::*;
use rsclientcerts::manager::{ManagerProxy, SlotType};
use std::ffi::CStr;
use std::sync::Mutex;
use std::thread;
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod backend_macos;
#[cfg(target_os = "windows")]
#[cfg(all(target_os = "windows", not(target_arch = "aarch64")))]
mod backend_windows;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use crate::backend_macos::Backend;
#[cfg(target_os = "windows")]
#[cfg(all(target_os = "windows", not(target_arch = "aarch64")))]
use crate::backend_windows::Backend;
struct ModuleState {
@@ -108,24 +107,12 @@ macro_rules! log_with_thread_id {
/// This gets called to initialize the module. For this implementation, this consists of
/// instantiating the `ManagerProxy`.
extern "C" fn C_Initialize(pInitArgs: CK_VOID_PTR) -> CK_RV {
extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV {
// This will fail if this has already been called, but this isn't a problem because either way,
// logging has been initialized.
let _ = env_logger::try_init();
if pInitArgs.is_null() {
return CKR_DEVICE_ERROR;
}
let init_args_ptr = unsafe { (*(pInitArgs as CK_C_INITIALIZE_ARGS_PTR)).pReserved };
if init_args_ptr.is_null() {
return CKR_DEVICE_ERROR;
}
let init_args_cstr = unsafe { CStr::from_ptr(init_args_ptr as *mut std::os::raw::c_char) };
let init_args = match init_args_cstr.to_str() {
Ok(init_args) => init_args,
Err(_) => return CKR_DEVICE_ERROR,
};
let mechanisms = if init_args == "RSA-PSS" {
let mechanisms = if static_prefs::pref!("security.osclientcerts.assume_rsa_pss_support") {
vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
} else {
vec![CKM_ECDSA, CKM_RSA_PKCS]
@@ -143,18 +130,11 @@ extern "C" fn C_Initialize(pInitArgs: CK_VOID_PTR) -> CK_RV {
mechanisms,
}) {
Some(_unexpected_previous_module_state) => {
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
log_with_thread_id!(info, "C_Initialize: module state previously set (this is expected on macOS - replacing it)");
}
#[cfg(target_os = "windows")]
{
log_with_thread_id!(
warn,
"C_Initialize: module state unexpectedly previously set (replacing it)"
"C_Initialize: replacing previously set module state (this is expected on macOS but not on Windows)"
);
}
}
None => {}
}
log_with_thread_id!(debug, "C_Initialize: CKR_OK");
@@ -1247,7 +1227,9 @@ static FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
/// comprising this module.
/// ppFunctionList must be a valid pointer.
#[no_mangle]
pub unsafe extern "C" fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
pub unsafe extern "C" fn OSClientCerts_C_GetFunctionList(
ppFunctionList: CK_FUNCTION_LIST_PTR_PTR,
) -> CK_RV {
if ppFunctionList.is_null() {
return CKR_ARGUMENTS_BAD;
}

View File

@@ -1108,7 +1108,7 @@ function writeLinesAndClose(lines, outputStream) {
* A unique substring of name of the dynamic library file of the module
* that should not be loaded.
*/
function checkPKCS11ModuleNotPresent(moduleName, libraryName) {
function checkPKCS11ModuleNotPresent(moduleName, libraryName = "undefined") {
let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
Ci.nsIPKCS11ModuleDB
);
@@ -1123,12 +1123,14 @@ function checkPKCS11ModuleNotPresent(moduleName, libraryName) {
moduleName,
`Non-test module name shouldn't equal '${moduleName}'`
);
if (libraryName != "undefined") {
ok(
!(module.libName && module.libName.includes(libraryName)),
`Non-test module lib name should not include '${libraryName}'`
);
}
}
}
/**
* Checks that the test module exists in the module list.
@@ -1142,7 +1144,7 @@ function checkPKCS11ModuleNotPresent(moduleName, libraryName) {
* @returns {nsIPKCS11Module}
* The test module.
*/
function checkPKCS11ModuleExists(moduleName, libraryName) {
function checkPKCS11ModuleExists(moduleName, libraryName = "undefined") {
let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
Ci.nsIPKCS11ModuleDB
);
@@ -1159,11 +1161,17 @@ function checkPKCS11ModuleExists(moduleName, libraryName) {
}
}
notEqual(testModule, null, "Test module should have been found");
notEqual(testModule.libName, null, "Test module lib name should not be null");
if (libraryName != "undefined") {
notEqual(
testModule.libName,
null,
"Test module lib name should not be null"
);
ok(
testModule.libName.includes(ctypes.libraryName(libraryName)),
`Test module lib name should include lib name of '${libraryName}'`
);
}
return testModule;
}

View File

@@ -16,10 +16,7 @@ const { TestUtils } = ChromeUtils.importESModule(
async function check_osclientcerts_module_loaded() {
// Loading happens asynchronously, so we have to wait for the notification.
await TestUtils.topicObserved("psm:load-os-client-certs-module-task-ran");
let testModule = checkPKCS11ModuleExists(
"OS Client Cert Module",
"osclientcerts"
);
let testModule = checkPKCS11ModuleExists("OS Client Cert Module");
// Check that listing the slots for the osclientcerts module works.
let testModuleSlotNames = Array.from(
@@ -38,7 +35,7 @@ async function check_osclientcerts_module_loaded() {
add_task(async function run_test() {
// Check that if we haven't loaded the osclientcerts module, we don't find it
// in the module list.
checkPKCS11ModuleNotPresent("OS Client Cert Module", "osclientcerts");
checkPKCS11ModuleNotPresent("OS Client Cert Module");
// Check that enabling the pref that loads the osclientcerts module makes it
// appear in the module list.
@@ -48,7 +45,7 @@ add_task(async function run_test() {
// Check that disabling the pref that loads the osclientcerts module (thus
// unloading the module) makes it disappear from the module list.
Services.prefs.setBoolPref("security.osclientcerts.autoload", false);
checkPKCS11ModuleNotPresent("OS Client Cert Module", "osclientcerts");
checkPKCS11ModuleNotPresent("OS Client Cert Module");
// Check that loading the module again succeeds.
Services.prefs.setBoolPref("security.osclientcerts.autoload", true);
@@ -56,5 +53,5 @@ add_task(async function run_test() {
// And once more check that unloading succeeds.
Services.prefs.setBoolPref("security.osclientcerts.autoload", false);
checkPKCS11ModuleNotPresent("OS Client Cert Module", "osclientcerts");
checkPKCS11ModuleNotPresent("OS Client Cert Module");
});

View File

@@ -6,7 +6,7 @@ skip-if = ["os == 'android'"]
["test_osclientcerts_module.js"]
skip-if = [
"os == 'linux'",
"os == 'android'",
"os == 'android'"
]
["test_pkcs11_module.js"]

View File

@@ -582,6 +582,7 @@ SECMOD_GetReadLock
SECMOD_InternaltoPubMechFlags
SECMOD_LoadModule
SECMOD_LoadUserModule
SECMOD_LoadUserModuleWithFunction
SECMOD_LockedModuleHasRemovableSlots
SECMOD_OpenUserDB
SECMOD_PubCipherFlagstoInternal

View File

@@ -109,6 +109,9 @@ fallible_collections = { version = "0.4", features = ["rust_1_57"] }
libz-rs-sys = { git = "https://github.com/memorysafety/zlib-rs", rev = "4aa430ccb77537d0d60dab8db993ca51bb1194c5", features = ["custom-prefix"], optional = true }
[target.'cfg(any(target_os = "macos",target_os = "ios", all(target_os = "windows", not(target_arch = "aarch64"))))'.dependencies]
osclientcerts = { path = "../../../../security/manager/ssl/osclientcerts" }
[target.'cfg(not(target_os = "android"))'.dependencies]
gkrust-uniffi-components = { path = "../../../components/uniffi-bindgen-gecko-js/components/", features = ["xpcom"] }
gkrust-uniffi-fixtures = { path = "../../../components/uniffi-bindgen-gecko-js/fixtures/", features = ["xpcom"], optional = true }

View File

@@ -85,6 +85,12 @@ extern crate fluent_fallback;
extern crate l10nregistry_ffi;
extern crate localization_ffi;
#[cfg(any(
target_os = "macos",
target_os = "ios",
all(target_os = "windows", not(target_arch = "aarch64"))))]
extern crate osclientcerts;
#[cfg(not(target_os = "android"))]
extern crate gkrust_uniffi_components;