Overview

BearSSL is an implementation of the SSL/TLS protocol (RFC 5246) written in C. It aims at offering the following features:

Be correct and secure. In particular, insecure protocol versions and choices of algorithms are not supported, by design; cryptographic algorithm implementations are constant-time by default.

Be small , both in RAM and code footprint. For instance, a minimal server implementation may fit in about 20 kilobytes of compiled code and 25 kilobytes of RAM.

Be highly portable . BearSSL targets not only “big” operating systems like Linux and Windows, but also small embedded systems and even special contexts like bootstrap code.

Be feature-rich and extensible. SSL/TLS has many defined cipher suites and extensions; BearSSL should implement most of them, and allow extra algorithm implementations to be added afterwards, possibly from third parties.

Status

Current version is 0.6. It is now considered beta-quality software: it successfully passes extensive test suites, and while not all intended features are present, new features should imply no breaking changes in API or ABI . There is no such thing as bug-free code, and I won’t claim that there is none in BearSSL; only that I looked real hard. Use in production applications is, in any case, at your own risk.

The versioning scheme is “major.minor.patch”. Backward compatibility, both at source and binary levels, should be maintained within the same major version; this means that, for instance, version 2.17 may contain more features than 2.14, but application code written for version 2.14 should be compilable with version 2.17, and code which was compiled against version 2.14 should be linkable against version 2.17. Such guarantees are not offered across major version numbers.

The “major 0” line explicitly denies any such guarantee. It is expected that successive 0.x versions will be incompatible with each other: API will change as some features are stabilised.

The “patch” component of a version number is for fixes that maintain compatibility and do not add any feature.

Download and Installation

The source code is available as a Git repository, cloneable through the following command:

git clone https://www.bearssl.org/git/BearSSL

Installation instructions are contained therein.

BearSSL source code for released versions can also be downloaded as an archive: bearssl-0.6.tar.gz

Older releases can be obtained from the change log.

Finally, the source tree can be explored through a Gitweb-powered interface.

Updates first appear in the Git repository, so cloning it is the right way to follow day-to-day development. Versions are “released” when some specific milestones are reached.

Legal Details

The whole of BearSSL is published under the MIT License. It basically means the following:

You can use and reuse the library as you wish, and modify it, and integrate it in your own code, and distribute it as is or in any modified form, and so on.

The only obligation that the license terms put upon you is that you acknowledge and make it clear that if anything breaks, it is not my fault, and I am not liable for anything, regardless of the type and amount of collateral damage. The license terms say that the copyright notice “shall be included in all copies or substantial portions of the Software”: this is how the disclaimer is “made explicit”. Basically, I have put it in every source file, so just keep it there.

Apart from the usage license, BearSSL implements cryptographic algorithms for which import, export, distribution and usage is subject to many subtleties that depend on the jurisdiction. A classic survey is available there, but of course these things tend to change over time, as the law makers try to keep pace with the unrelenting scientific and technological progress.

BearSSL was written in Canada and is distributed from a server located on Canadian soil. It is my understanding, as a normal citizen (and certainly not a professional of the law), that BearSSL falls under the “open source exception” which makes its distribution under its current form fully compliant to Canadian law. Note, though, that if you download it from another country, you are not only exporting BearSSL from Canada but also importing it into that other country, and additional laws may apply. This is, in crude terms, your legal problem, not mine; I am not doing the export (and subsequent import), you are.

Documentation

API documentation, at the function call level, is published there. This is generated with Doxygen from comments in a specific format in the header files (located in the inc/ subdirectory in the source archive).

Detailed documentation, on library usage, API structure, design, and generally how it was done and why, is of paramount importance to the security of the library. Indeed, it is extremely hard to show whether any piece of code does its intended job correctly, and the only practical way known so far is to have a clear, well-documented design and specification, and have many people look at it.

Therefore, there is an ongoing effort to accumulate such documents. Right now, they are available there and more will be added over time.

Features

This section gives a short list of features of BearSSL, some already implemented, others planned for a future version. See also the roadmap.

Already Implemented

A static linking model in which only algorithms that are actually used get pulled into the linked binary. This is done through appropriate usage of function pointers; there is no need to recompile BearSSL with specific preprocessor options to obtain such a trimming.

A state-machine API in which data is pushed into or retrieved from a context structure, without needing callback functions for I/O. This structure makes it easier to use BearSSL for non-stream mediums (e.g. to use “messages” as part of the EAP authentication framework), and to run several concurrent connections in a mono-threaded context (with a central poll() or select() to manage actual I/O operations). A simplified stream-like API with callbacks for low-level I/O is still provided as an optional wrapper.

No dynamic allocation whatsoever . There is not a single malloc() call in all the library. In fact, the whole of BearSSL requires only memcpy() , memmove() , memcmp() and strlen() from the underlying C library. This makes it utterly portable even in the most special, OS-less situations. (On “big” systems, BearSSL will automatically use a couple more system calls to access the OS-provided clock and random number generator.) On big desktop and server OS, this feature still offers an interesting characteristic: immunity to memory leaks and memory-based DoS attacks. Outsiders cannot make BearSSL allocate megabytes of RAM since BearSSL does not actually know how to allocate RAM at all.

Client and server are both implemented.

TLS 1.0, TLS 1.1 and TLS 1.2 are supported. By design, SSL 2.0 and SSL 3.0 are not supported, since these earlier protocol versions have irreparable vulnerabilities.

RSA, ECDH and ECDHE key exchange are supported. The ECDHE key exchange offers “Forward Secrecy”, a desirable property by which actual key exchange secrets are transient and destroyed after usage, thereby presumably immune to ulterior theft in case of full machine compromise. By design, DHE is not supported: it has no real advantage over ECDHE, and ECDHE is faster. More importantly, it is hard to ensure that DHE is used properly, since the protocol does not allow the server to document the proper range for DH private keys.

Minimal X.509 certificate validation is implemented. While the engine does not support all the bells and whistles of X.509 validation, it still enforces the basics: subject/issuer DN matching, notBefore/notAfter dates, basic constraints, and key usage extension. Optionally, the client will also verify that the server’s certificate contains the intended dNSName (in the Subject Alt Name extension, or in the Common Name if the SAN extension is missing); this check can handle a “wildcard” at the start of a name. RSA and ECDSA signatures are supported, with all the “classical” hash functions (SHA-1, and the SHA-2 family from SHA-224 to SHA-512). There again, MD5 is voluntarily excluded. The validation engine “fails safe” in that it rejects any certificate that triggers an unsupported feature in a critical extension. However, it must be noted that the minimal engine does not implement revocation checks.

Client certificates are supported both on the client side and the server side. RSA signatures, ECDSA signatures, and full static ECDH authentication methods can be used.

For size-constrained clients, a known key model is provided, in which the client already knows by some out-of-band mechanism the public key of the server, thereby skipping any validation step and avoding the need to embed the X.509 validation engine.

AES/GCM, AES/CCM, AES/CBC, 3DES/CBC and ChaCha20+Poly1305 encryption algorithms are supported. Several implementations are provided for each algorithm, incarnating various trade-offs between performance and code size. The implementations selected by default are constant-time: they make no memory access whose address depends on secret data, and they make no conditional jump based on secret data. These implementations are thus immune to side-channel attacks that exploit these kinds of leak. AES-NI opcodes on recent x86 CPU are used to run both AES and GHASH (the MAC part of GCM) with much improved performance on systems that support these opcodes. Similary, the AES hardware support on POWER8 systems are leveraged for improved performance. The RSA and elliptic curve implementations are also constant-time. They should also properly react to invalid input data (e.g. an input point which is not actually a curve point). Elliptic curves secp256r1 (P-256), secp384r1 (P-384) and secp521r1 (P-521) are supported; Curve25519 is also supported (for ECDHE key exchange).

RSA and EC key pair generation is implemented. This allows for on-board generation of such secrets, which is considered a better idea for security than external generation and import. Note that RSA key generation is expensive.

A simple session cache is provided, for handling abbreviated handshakes when a client comes back. The cache needs 100 bytes of RAM per remembered session. Both the client and server codes handle session resumption.

Secure Renegotiation (RFC 5746) is implemented. Renegotiations are rejected if that extension is not supported by the peer. A configurable flag also allows rejecting all renegotiations.

Maximum Fragment Length extension is used by the client code to negociate a smaller maximum record size. This allows running with even less RAM; unfortunately, as the extension is defined in RFC 6066, only the client may use that extension effectively, so a RAM-constrained server cannot ask for smaller records.

ALPN extension (RFC 7301). This is needed for proper interaction with HTTP/2.

Not Yet Implemented

Additional algorithm implementations are planned. In particular: Optimised implementations for ARM processors, especially small ARM (like the Cortex-M0 line) which are notoriously challenged in that respect. Better big integer code for generic EC; the current implementations are constant-time and portable, but somewhat slow. Support for EdDSA (this still needs some clearer view of future standardisation, in particular symbolic identifiers). EdDSA for client authentication, and EdDSA for signing certificates, are problematic features in the context of BearSSL (they require buffering potentially large amounts of data); but for server-side authentication, EdDSA support should be doable.

Extra functions to make BearSSL a more generic cryptographic library. In particular, production of signed certificate requests and self-signed certificates are needed for safe usage of some applications: ideally, a SSL server should generate its own private key, not have it imported (key pair generation is now implemented).

DTLS. Since BearSSL already works as a state machine, interface with a packet-based transport medium should be relatively easy; but DTLS still has a few features that need some specific code.

TLS-1.3, when it is specified as a RFC (I don’t want to chase drafts and have compatibility breaks due to changing specifications; RFC are immutable, so I wait for the RFC).

Documentation. Lots of documentation. Since it is extremely difficult, and mostly impossible in the general case, to prove that any significant piece of code is correct, we should rely on the next best thing, which is thorough documentation, both for the API usage (man pages for all functions…) and for the complete internal design. This Web site will be enriched over time, with new documents, as I write them.

Any comment or suggestion may be sent to me (Thomas Pornin) at: <pornin@bolet.org>