Chute Devs

Migrating from BoringSSL to LibreSSL — Why and How

Hello everyone.

In our latest engine update, we migrated our TLS library from BoringSSL to LibreSSL. This post explains the motivation behind this change and the technical work involved.

Background

Chute’s proxy engine handles a wide range of TLS operations: securing proxy connections, performing MITM decryption, generating leaf certificates on the fly, and negotiating every modern TLS protocol from TLS 1.2 to TLS 1.3 with QUIC.

Since its inception, the engine relied on BoringSSL — Google’s fork of OpenSSL — for all cryptographic operations. BoringSSL served us well through several years of development. However, a breaking change in BoringSSL forced our hand.

The Breaking Point: Removed Cipher Methods

In a recent BoringSSL update, Google removed support for several legacy cipher suites. While this makes sense for a web browser (Chrome, the primary consumer of BoringSSL), it created a problem for a proxy engine like ours.

Proxy servers must interoperate with a diverse ecosystem. Some Shadowsocks servers still use older cipher configurations. Some VMess servers require specific encryption methods that BoringSSL no longer supports. When these ciphers disappeared from BoringSSL, suddenly certain proxy configurations stopped working.

We had three options:

  1. Fork BoringSSL and restore the removed ciphers — heavy maintenance burden
  2. Use two SSL libraries — one modern, one legacy — doubles the complexity
  3. Migrate to LibreSSL — a clean, security-focused fork of OpenSSL that maintains a broader cipher suite

We chose LibreSSL.

Why LibreSSL?

LibreSSL is a version of the TLS/crypto stack developed by the OpenBSD project. It was forked from OpenSSL 1.0.1g in 2014 with a strong focus on code quality, security, and API stability. Key advantages for our use case:

  • Broader cipher support: LibreSSL v4.0.0 retains compatibility with cipher suites that BoringSSL removed
  • Clean API: LibreSSL’s API is stable and well-documented, derived from OpenSSL but with deprecated cruft removed
  • Security-first: The OpenBSD team is known for rigorous security audits and defensive coding practices
  • Active maintenance: LibreSSL receives regular updates with security fixes and new TLS features

The Migration

The migration touched several subsystems:

1. Header and Build System Changes

We replaced all #include <openssl/...> paths that previously pointed to BoringSSL with the LibreSSL equivalents. The Xcode project was updated to reference the LibreSSL static libraries instead of BoringSSL. For our custom build scripts that compile SSL libraries for multiple Apple platforms, we swapped the source repositories and build targets.

2. TLS Connection Layer

Our TLS connection layer uses the OpenSSL BIO and SSL API. LibreSSL maintains a compatible API surface, so most of the code compiled without changes. We did need to update a few areas:

  • Cipher string normalization: BoringSSL and LibreSSL use slightly different cipher name conventions. We added a mapping layer to normalize cipher suite names
  • Certificate verification: LibreSSL’s verification defaults differ from BoringSSL’s. We reviewed every verification call to ensure consistent behavior
  • Session resumption: LibreSSL’s session ticket handling differs slightly; we updated our session cache logic

3. QUIC Transport

Our QUIC implementation uses the TLS stack for QUIC handshakes. The underlying QUIC library supports both BoringSSL and LibreSSL backends through compile-time flags. We switched the build to target LibreSSL and updated the necessary QUIC-TLS integration points.

4. MITM Certificate Generation

Our MITM engine generates leaf certificates on the fly using standard X.509 APIs. LibreSSL provides full support for X.509 generation, key generation, and certificate signing. The migration was straightforward — the APIs are nearly identical.

5. Testing

We ran our full test suite against the LibreSSL build. The main issues found were:

  • Ed25519 key support: LibreSSL handles Ed25519 keys differently; updated key serialization
  • Default cipher ordering: LibreSSL defaults to a different cipher preference order; adjusted where necessary
  • Error code mapping: TLS error return values were normalized to a common internal representation

What This Means for Users

For Chute users, this migration is transparent. All existing proxy configurations continue to work. The main benefit is forward compatibility: protocols that depend on specific cipher suites will not break when BoringSSL removes those ciphers.

For developers, it means our engine is now aligned with a TLS library that prioritizes stability and compatibility alongside security — a better fit for a proxy engine than a browser-focused TLS stack.

The migration from BoringSSL to LibreSSL was a necessary step to maintain broad protocol compatibility. LibreSSL’s stability-focused approach aligns better with our needs as a proxy engine that must interoperate with diverse server configurations. Most of the code compiled without changes, and the result is a stronger foundation for future protocol support.

If you have technical questions about the migration, feel free to reach out at Support.

Thanks.

Chute Devs