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.
Current version is the first release, under the number “0.1”. It is considered alpha-quality software, which means that it runs but it probably has bugs, some of which being certainly exploitable vulnerabilities. A lot more testing and documentation is needed before BearSSL can be deemed usable in production.
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.
BearSSL source code can be downloaded as an archive: bearssl-0.1.tar.gz
Installation instructions are contained therein.
The source code is also available as a Git repository, cloneable through the following command:
git clone https://www.bearssl.org/git/BearSSL
Finally, the source tree can be explored through a Gitweb-powered interface.
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.
This section lists the features of BearSSL, some already implemented, others planned for a future version.
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()
orselect()
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 onlymemcpy()
,memmove()
,memcmp()
andstrlen()
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.
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/CBC and 3DES/CBC 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.
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.
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.
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.
Not Yet Implemented
Additional algorithm implementations are planned. In particular:
ChaCha20+Poly1305, as per RFC 7905, should offer an especially nice performance/footprint ratio.
AES implementations using the AES-NI opcodes on modern x86 CPU.
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 RSA and for generic EC; the current implementations are constant-time and portable, but quite slow.
Support for Curve25519 and EdDSA (when they finally get enshrined as actual RFC, not drafts).
Client certificates. Since BearSSL already has both client and server parts, all the essential components are there (signature generation and verification, ongoing hashing of handshake messages, certificate path validation…) but some extra API design work is still needed, in particular with regards to what parts of the client certificate should be extracted as “identity” by the server.
Extra functions to make BearSSL a more generic cryptographic library. In particular, key pair generation and 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).
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.
ALPN extension (RFC 7301). This is needed for proper interaction with HTTP/2.
More behavioural flags, in particular a way to disable renegotiations altogether (an HTTP/2 requirement).
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>