Chrome: From NSS to OpenSSL
Design Doc DRAFT
Last edited on: 2014-01-26
Provide a consistent experience for all cryptographic applications within Chromium and Chromium OS, with reliable (and secure) performance in the common-case and hardware-accelerated performance (on all platforms) when supported. Support the variety of efforts for in-process isolation (eg: profiles / StoragePartitions), such as SSL/TLS session caches and certificate trust and distrust decisions. Reduce maintenance cost by having a single supported interface, allowing for more rapid innovations in performance and rapid responses to security issues.
Currently, Chromium supports two different SSL/cryptographic backends. On Windows, OS X, iOS, Linux, and Chromium OS, Chromium uses NSS. On Android, Chromium uses OpenSSL. This split is further reflected throughout the cryptographic services exposed by Chromium - from basic hashing, the SSL/TLS implementation within net/, extensions, WebRTC’s implementation of DTLS (and SRTP), the Clear Key EME Content Decryption Module, and Blink’s implementation of WebCrypto, to name a few, with dual implementations of almost all core functionality. The exception to this split is certificate verification - on Windows, OS X, and Android, Chromium uses the native certificate verification functionality.
Prior to Chrome 6, Chromium supported even more implementations - supporting the native OS implementations on Windows (CryptoAPI and SChannel) and OS X (CDSA/CSSM and Secure Transport). However, Chromium transitioned away from these implementations for similar reasons as this document proposes - increased maintenance cost, decreased agility, and decreased performance.
The choice of NSS as the common desktop implementation at the time was based on the fact that NSS was already in use for the Linux port. The choice between NSS and OpenSSL for the Linux port was based on several factors; NSS was in use by the then-dominant browser (Mozilla Firefox, as Netscape originally developed NSS for Netscape Navigator), it supported smart cards using an industry standard API (PKCS#11), and had robust RFC 3280/5280 certificate path building and verification code, which is absolutely vital for being able to access public websites, due to the frequent edge cases and misconfigurations with respect to certificate chains.
There are cons to maintaining the existing dual stack nature, such as duplicated efforts implementing features, such as those listed in the Background, as well as in fixing security issues that appear in both implementations (eg: BEAST, Lucky 13 ).
There are also pros to maintaining the existing dual stack. Most notable is that when suggesting or implementing improvements to TLS - such as ChaCha20/Poly1305, Channel ID, or False Start - implementing multiple times can highlight issues in the specification or potential implementation issues that other implementers may experience.
The question is whether to switch Android to NSS or all other platforms to OpenSSL. At first glance, it would seem “less” work to switch Chromium on Android to use NSS. However, this is not entirely true. When powering WebView, Chromium on Android uses the Android system-provided OpenSSL library - something not available to applications building with the Android NDK (like Chrome for Android or other Chromium-based Android applications). This helps reduce memory usage by having a single shared library in memory. To accomplish this with NSS, NSS would have to be part of the Android base image - which would still increase memory usage, as most other Android (native) services would still use OpenSSL.
Additionally, the increased redundancy and abstraction within NSS would be detrimental to the overall performance of Android.
Switching to OpenSSL, however, has the opportunity to bring significant performance and stability advantages to iOS, Mac, Windows, and ChromeOS immediately out of the gate. Switching Linux to use OpenSSL will take longer, due to the desire to continue to support PKCS#11-based smart card authentication, which will require more work. The biggest risk/cost to such a switch is no longer being able to help Firefox benefit from these efforts, nor benefiting from Firefox’s efforts in these areas.
To transition from SSLClientSocketNSS to SSLClientSocketOpenSSL, support for using the platform-native client certificate handles (eg: via CryptoAPI and Keychain Services, respectively) is needed. This is similar to the requirement when transitioning to SSLClientSocketNSS from SSLClientSocketWin/SSLClientSocketMac.
Support for TPM-backed client certificates is required. Currently, the TPM is exposed via chapsd and a PKCS#11 library that communicates with chapsd over DBus.
Depending on the desired timeframes, there are two possible outcomes:
Because Chromium has historically used NSS, Linux users may have already generated certificates or other credentials and installed them into the NSS shared DB utilized by Chromium.
Additionally, Linux users MAY be utilizing PKCS#11-based smart cards - although the extent is currently unknown.
The following steps are to be taken:
Based on these numbers, it should be decided whether to support PKCS#11 smart cards on Linux and whether to migrate the NSS DB key storage to a Chromium-defined key storage.
For the foreseeable future, Windows will continue to use the platform-native certificate verification APIs.
Due to significant limitations in the underlying platform’s capabilities for building certificate chains, the OS X certificate verification will be ported to a hybrid of the newly-developed, OpenSSL-backed certificate path building engine, with trust decisions continuing to be provided by Keychain Services.
However, Keychain-defined trust exceptions (where specific CDSA/CSSM error codes are whitelisted for certain certificates/hosts) are unlikely to be supported.
iOS will transition to the OpenSSL-backed certificate path building engine, using the same trust store as ChromeOS.
ChromeOS will transition to the OpenSSL-backed certificate path building engine, and will continue using its existing trust store.
Trust decisions will need to be migrated from the ChromeOS users profile into a form recognized by the OpenSSL engine. However, these trust decisions are simple due to the UI exposed on ChromeOS.
Linux will transition to the OpenSSL-backed certificate path building engine.
The source of trust/distrust decisions is contingent upon PKCS#11 support, but may make use of p11-kit as the preferred trust backend.
No special considerations are known to exist for WebRTC, as it supports using both NSS and OpenSSL as cryptographic engines.
Certain Pepper APIs expose the ability to initiate SSL/TLS connections. However, these interfaces are minimal and expected to be equivalent between NSS and OpenSSL.
There may be existing Pepper plugins that make use of src/crypto or NSS, from within the Pepper sandbox. Such plugins are shipping their *own* copy of NSS, and can continue to do so, much in the way that “any” code can be run within the Pepper sandbox. However, they’re encouraged to use OpenSSL.
On Linux/ChromeOS, there exists special considerations to permit using a “system” NSS from within the sandbox, by preloading the NSS shared objects. When Linux/ChromeOS transitions away from NSS, so too will this warmup code.
As sandboxed plugins should not be depending on any state from the ‘host’ environment, this is arguably a “bug” today that will need to be resolved when transitioning to OpenSSL.
The primary purpose of such pre-warming is:
1) Load any necessary shared objects needed by NSS
With OpenSSL, this is not needed, as Chrome will not be loading a “shared” OpenSSL. Pepper applications are expected to link in their dependencies - including OpenSSL, if they have such a dependency.
2) Load /dev/urandom within the sandbox for use as an entropy source.
With Pepper, applications can request random data from the host using supported Pepper APIs. Modifications to OpenSSL to supply an alternate “system” entropy source (as opposed to directly open /dev/urandom) will be included in src/crypto - for Pepper plugins that bundle Chromium’s crypto
3) Load certificate trust databases
This is again a “bug”, in that it is not a “supported” Pepper API and not meant to be utilized by Pepper plugins.
No special considerations are known to exist for the Clear Key CDM included as part of Chromium. The Clear Key CDM makes use of the crypto/ interfaces, which are interoperable with the NSS implementations.
WebCrypto development is currently focused on NSS support, and will continue to be for the immediate future based on plans. However, because the WebCrypto API does not define specific requirements with respect to Key Storage, Blink should be able to seamlessly transition from the NSS implementation to the OpenSSL implementation.
Note that the OpenSSL implementation is being pursued in parallel, but is slightly less feature complete than NSS at this time.
The following items require new code to be developed before the OpenSSL equivalent classes from src/crypto and src/net can be transitioned to.
The remoting host makes use of TLS server sockets, and thus it’s necessary to implement SSLServerSocketOpenSSL.
This is a relatively simple, straight forward implementation.
To support using client certificates on Windows, the relevant EVP methods for supporting RSA/ECDSA operations using CryptoAPI will need to be developed.
The OS integration code already exists for NSS, this is merely adopting it to the OpenSSL API.
To support using client certificates on OS X, the relevant EVP methods for supporting RSA/ECDSA operations using Keychain Services/CDSA will need to be developed.
The OS integration code already exists for NSS, this is merely adopting it to the OpenSSL API.
On Linux, uses of the <keygen> tag and the application/x-x509-user-cert mime type cause keys and certificates to be imported into the NSS shared DB ( ~/.pki/nssdb ). Depending on the user metrics related to client certificate authentication , it may be necessary to export keys/certificates from the common store into a Chromium-defined database for use with OpenSSL.
This is similar to the existing Chromium-defined database for Channel ID storage.
Alternatively, support for PKCS#11 may mean that Chromium will load the NSS “softoken” PKCS#11 module to continue reading/using the existing database, while generating/storing all new keys into its own database.
OpenSSL currently provides a single callback for certificate verification, and expects that callback to complete synchronously. However, callbacks for retrieving a client certificate and for retrieving a Channel ID are both allowed to be completed asynchronously.
A patch to OpenSSL to support asynchronous verification will be needed. Patching OpenSSL with Chromium is fine, as we will distribute OpenSSL together with Chromium on all platforms (eg: there will be no reliance on a “System OpenSSL”). The exception is Chromium WebView for Android, which links against Android’s OpenSSL, but WebView will always be shipped simultaneously with the platform, and thus patches can be integrated with AOSP upstream.
A directed, cyclic graph traversal engine, using the strategies described in RFC 4158, will need to be developed, since OpenSSL lacks one, while NSS has one (via libpkix).
To ensure both the correctness of the implementation and to avoid a “flag day” for Linux, the path building should be agnostic to the underlying cryptographic library. This is to permit comparing the library (and performance) using NSS against libpkix and comparing the NSS implementation against the OpenSSL implementation, to provide a smooth transition.
Such a path building engine minimally needs to support:
To support smart cards on Linux, a bridge between OpenSSL’s core abstractions (eg: EVP_*) and PKCS#11’s abstractions (C_Sign/C_Verify/*) is needed.
Some internal Pepper plugins are known to be relying on side-effects of NSS being initialized the way it currently is by Chromium. These are design issues with the plugins and implementation details not meant to be exposed to Pepper.