| # BoringSSL API Conventions | |
| This document describes conventions for BoringSSL APIs. The [style | |
| guide](./STYLE.md) also includes guidelines, but this document is targeted at | |
| both API consumers and developers. API documentation in BoringSSL may assume | |
| these conventions by default, rather than repeating them for every function. | |
| ## Documentation | |
| All supported public APIs are documented in the public header files, found in | |
| `include/openssl`. The API documentation is also available | |
| [online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html). | |
| Experimental public APIs are found in `include/openssl/experimental`. Use of | |
| these will likely be incompatible with changes in the near future as they are | |
| finalized. | |
| ## Forward declarations | |
| Do not write `typedef struct foo_st FOO` or try otherwise to define BoringSSL's | |
| types. Including `openssl/base.h` (or `openssl/ossl_typ.h` for consumers who | |
| wish to be OpenSSL-compatible) will forward-declare each type without importing | |
| the rest of the library or invasive macros. | |
| ## Error-handling | |
| Most functions in BoringSSL may fail, either due to allocation failures or input | |
| errors. Functions which return an `int` typically return one on success and zero | |
| on failure. Functions which return a pointer typically return `NULL` on failure. | |
| However, due to legacy constraints, some functions are more complex. Consult the | |
| API documentation before using a function. | |
| On error, most functions also push errors on the error queue, an `errno`-like | |
| mechanism. See the documentation for | |
| [err.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/err.h.html) | |
| for more details. | |
| As with `errno`, callers must test the function's return value, not the error | |
| queue to determine whether an operation failed. Some codepaths may not interact | |
| with the error queue, and the error queue may have state from a previous failed | |
| operation. After checking for failure, the caller can then inspect the error | |
| queue in the failure case for details. | |
| As a notable exception, some functions in the SSL/TLS library use a multi-step | |
| process to indicate failure: First, the return value indicates whether the | |
| operation failed. Then, `SSL_get_error` indicates whether the failure was due to | |
| an error (`SSL_ERROR_SSL`) or some recoverable condition (e.g. | |
| `SSL_ERROR_WANT_READ`). In the former case, the caller can use the error queue | |
| for more information. | |
| When ignoring a failed operation, it is recommended to call `ERR_clear_error` to | |
| avoid the state interacting with future operations. Failing to do so should not | |
| affect the actual behavior of any functions, but may result in errors from both | |
| operations being mixed in error logging. We hope to | |
| [improve](https://bugs.chromium.org/p/boringssl/issues/detail?id=38) this | |
| situation in the future. | |
| Where possible, avoid conditioning on specific reason codes and limit usage to | |
| logging. The reason codes are very fine-grained and tend to leak details of the | |
| library's internal structure. Changes in the library often have a side effect of | |
| changing the exact reason code returned. | |
| ## Memory allocation | |
| BoringSSL allocates memory via `OPENSSL_malloc`, found in `mem.h`. Use | |
| `OPENSSL_free`, found in the same header file, to release it. BoringSSL | |
| functions will fail gracefully on allocation error, but it is recommended to use | |
| a `malloc` implementation that `abort`s on failure. | |
| To re-iterate the POSIX standard, `OPENSSL_malloc` will satisfy the following | |
| post-conditions. | |
| - The allocated memory is suitably aligned for any type that fits into the | |
| requested size or less. | |
| - The bytes delimited from the beginning of the allocation pointed at by the | |
| pointer until `size` bytes after the pointer, exclusive, are valid for write. | |
| - `size` must have been no more than `PTRDIFF_MAX` bytes. | |
| ## Pointers and slices | |
| Unless otherwise specified, pointer parameters that refer to a single object, | |
| either as an input or output parameter, may not be `NULL`. In this case, | |
| BoringSSL often will not check for `NULL` before dereferencing, so passing | |
| `NULL` may crash or exhibit other undefined behavior. (Sometimes the function | |
| will check for `NULL` anyway, for OpenSSL compatibility, but we still consider | |
| passing `NULL` to be a caller error.) | |
| Pointer parameters may also refer to a contiguous sequence of objects, sometimes | |
| referred to as a *slice*. These will typically be a pair of pointer and length | |
| parameters named like `plaintext` and `plaintext_len`, or `objs` and `num_objs`. | |
| We prefer the former for byte buffers and the latter for sequences of other | |
| types. The documentation will usually refer to both parameters together, e.g. | |
| "`EVP_DigestUpdate` hashes `len` bytes from `data`." | |
| Parameters in C and C++ that use array syntax, such as | |
| `uint8_t out[SHA256_DIGEST_LENGTH]`, are really pointers. In BoringSSL's uses of | |
| this syntax, the pointer must point to the specified number of values. | |
| In other cases, the documentation will describe how the function parameters | |
| determine the slice's length. For example, a slice's length may be measured in | |
| units other than element count, multiple slice parameters may share a length, or | |
| a slice's length may be implicitly determined by other means like RSA key size. | |
| By default, BoringSSL follows C++'s | |
| [slice conventions](https://davidben.net/2024/01/15/empty-slices.html) | |
| for pointers. That is, unless otherwise specified, pointers for non-empty | |
| (non-zero length) slices must be represented by a valid pointer to that many | |
| objects in memory. Pointers for empty (zero length) slices must either be `NULL` | |
| or point within some sequence of objects of a compatible type. | |
| WARNING: The dangling, non-null pointer used by Rust empty slices may *not* be | |
| passed into BoringSSL. Rust FFIs must adjust such pointers to before passing to | |
| BoringSSL. For example, see the `FfiSlice` abstraction in `bssl-crypto`. (We may | |
| relax this if pointer arithmetic rules in C/C++ are adjusted to permit Rust's | |
| pointers. Until then, it is impractical for a C/C++ library to act on such a | |
| slice representation. See | |
| [this document](https://davidben.net/2024/01/15/empty-slices.html) for more | |
| discussion.) | |
| In some cases, OpenSSL compatibility requires that a function will treat `NULL` | |
| slice pointers differently from non-`NULL` pointers. Such behavior will be | |
| described in documentation. For examples, see `EVP_EncryptUpdate`, | |
| `EVP_DigestSignFinal`, and `HMAC_Init_ex`. Callers passing potentially empty | |
| slices into such functions should take care that the `NULL` case is either | |
| unreachable or still has the desired behavior. | |
| If a `const char *` parameter is described as a "NUL-terminated string" or a | |
| "C string", it must point to a sequence of `char` values containing a NUL (zero) | |
| value, which determines the length. Unless otherwise specified, the pointer may | |
| not be `NULL`, matching the C standard library. | |
| For purposes of C and C++'s | |
| [strict aliasing](https://en.cppreference.com/w/c/language/object#Strict_aliasing) | |
| requirements, objects passed by pointers must be accessible as the specified | |
| type. `uint8_t` may be assumed to be the same type as `unsigned char` and thus | |
| may be the pointer type for all object types. BoringSSL does not support | |
| platforms where `uint8_t` is a non-character type. However, there is no | |
| strict aliasing sanitizer, very few C and C++ codebases are valid by strict | |
| aliasing, and BoringSSL itself has some | |
| [known strict aliasing bugs](https://crbug.com/boringssl/444), thus we strongly | |
| recommend consumers build with `-fno-strict-aliasing`. | |
| Pointer parameters additionally have ownership and lifetime requirements, | |
| discussed in the section below. | |
| ## Object initialization and cleanup | |
| BoringSSL defines a number of structs for use in its APIs. It is a C library, | |
| so the caller is responsible for ensuring these structs are properly | |
| initialized and released. Consult the documentation for a module for the | |
| proper use of its types. Some general conventions are listed below. | |
| ### Heap-allocated types | |
| Some types, such as `RSA`, are heap-allocated. All instances will be allocated | |
| and returned from BoringSSL's APIs. It is an error to instantiate a heap- | |
| allocated type on the stack or embedded within another object. | |
| Heap-allocated types may have functions named like `RSA_new` which allocates a | |
| fresh blank `RSA`. Other functions may also return newly-allocated instances. | |
| For example, `RSA_parse_public_key` is documented to return a newly-allocated | |
| `RSA` object. | |
| Heap-allocated objects must be released by the corresponding free function, | |
| named like `RSA_free`. Like C's `free` and C++'s `delete`, all free functions | |
| internally check for `NULL`. It is redundant to check for `NULL` before calling. | |
| A heap-allocated type may be reference-counted. In this case, a function named | |
| like `RSA_up_ref` will be available to take an additional reference count. The | |
| free function must be called to decrement the reference count. It will only | |
| release resources when the final reference is released. For OpenSSL | |
| compatibility, these functions return `int`, but callers may assume they always | |
| successfully return one because reference counts use saturating arithmetic. | |
| C++ consumers are recommended to use `bssl::UniquePtr` to manage heap-allocated | |
| objects. `bssl::UniquePtr<T>`, like other types, is forward-declared in | |
| `openssl/base.h`. Code that needs access to the free functions, such as code | |
| which destroys a `bssl::UniquePtr`, must include the corresponding module's | |
| header. (This matches `std::unique_ptr`'s relationship with forward | |
| declarations.) Note, despite the name, `bssl::UniquePtr` is also used with | |
| reference-counted types. It owns a single reference to the object. To take an | |
| additional reference, use the `bssl::UpRef` function, which will return a | |
| separate `bssl::UniquePtr`. | |
| ### Stack-allocated types | |
| Other types in BoringSSL are stack-allocated, such as `EVP_MD_CTX`. These | |
| types may be allocated on the stack or embedded within another object. | |
| However, they must still be initialized before use. | |
| Every stack-allocated object in BoringSSL has a *zero state*, analogous to | |
| initializing a pointer to `NULL`. In this state, the object may not be | |
| completely initialized, but it is safe to call cleanup functions. Entering the | |
| zero state cannot fail. (It is usually `memset(0)`.) | |
| The function to enter the zero state is named like `EVP_MD_CTX_init` or | |
| `CBB_zero` and will always return `void`. To release resources associated with | |
| the type, call the cleanup function, named like `EVP_MD_CTX_cleanup`. The | |
| cleanup function must be called on all codepaths, regardless of success or | |
| failure. For example: | |
| uint8_t md[EVP_MAX_MD_SIZE]; | |
| unsigned md_len; | |
| EVP_MD_CTX ctx; | |
| EVP_MD_CTX_init(&ctx); /* Enter the zero state. */ | |
| int ok = EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) && | |
| EVP_DigestUpdate(&ctx, "hello ", 6) && | |
| EVP_DigestUpdate(&ctx, "world", 5) && | |
| EVP_DigestFinal_ex(&ctx, md, &md_len); | |
| EVP_MD_CTX_cleanup(&ctx); /* Release `ctx`. */ | |
| Note that `EVP_MD_CTX_cleanup` is called whether or not the `EVP_Digest*` | |
| operations succeeded. More complex C functions may use the `goto err` pattern: | |
| int ret = 0; | |
| EVP_MD_CTX ctx; | |
| EVP_MD_CTX_init(&ctx); | |
| if (!some_other_operation()) { | |
| goto err; | |
| } | |
| uint8_t md[EVP_MAX_MD_SIZE]; | |
| unsigned md_len; | |
| if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) || | |
| !EVP_DigestUpdate(&ctx, "hello ", 6) || | |
| !EVP_DigestUpdate(&ctx, "world", 5) || | |
| !EVP_DigestFinal_ex(&ctx, md, &md_len) { | |
| goto err; | |
| } | |
| ret = 1; | |
| err: | |
| EVP_MD_CTX_cleanup(&ctx); | |
| return ret; | |
| Note that, because `ctx` is set to the zero state before any failures, | |
| `EVP_MD_CTX_cleanup` is safe to call even if the first operation fails before | |
| `EVP_DigestInit_ex`. However, it would be illegal to move the `EVP_MD_CTX_init` | |
| below the `some_other_operation` call. | |
| As a rule of thumb, enter the zero state of stack-allocated structs in the | |
| same place they are declared. | |
| C++ consumers are recommended to use the wrappers named like | |
| `bssl::ScopedEVP_MD_CTX`, defined in the corresponding module's header. These | |
| wrappers are automatically initialized to the zero state and are automatically | |
| cleaned up. | |
| ### Data-only types | |
| A few types, such as `SHA_CTX`, are data-only types and do not require cleanup. | |
| These are usually for low-level cryptographic operations. These types may be | |
| used freely without special cleanup conventions. | |
| ### Ownership and lifetime | |
| When working with allocated objects, it is important to think about *ownership* | |
| of each object, or what code is responsible for releasing it. This matches the | |
| corresponding notion in higher-level languages like C++ and Rust. | |
| Ownership applies to both uniquely-owned types and reference-counted types. For | |
| the latter, ownership means the code is responsible for releasing one | |
| reference. Note a *reference* in BoringSSL refers to an increment (and eventual | |
| decrement) of an object's reference count, not `T&` in C++. Thus, to "take a | |
| reference" means to increment the reference count and take ownership of | |
| decrementing it. | |
| As BoringSSL's APIs are primarily in C, ownership and lifetime obligations are | |
| not rigorously annotated in the type signatures or checked at compile-time. | |
| Instead, they are described in | |
| [API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html). | |
| This section describes some conventions. | |
| Unless otherwise documented, functions do not take ownership of pointer | |
| arguments. The pointer typically must remain valid for the duration of the | |
| function call. The function may internally copy information from the argument or | |
| take a reference, but the caller is free to release its copy or reference at any | |
| point after the call completes. | |
| A function may instead be documented to *take* or *transfer* ownership of a | |
| pointer. The caller must own the object before the function call and, after | |
| transfer, no longer owns it. As a corollary, the caller may no longer reference | |
| the object without a separate guarantee on the lifetime. The function may even | |
| release the object before returning. Callers that wish to independently retain a | |
| transferred object must therefore take a reference or make a copy before | |
| transferring. Callers should also take note of whether the function is | |
| documented to transfer pointers unconditionally or only on success. Unlike C++ | |
| and Rust, functions in BoringSSL typically only transfer on success. | |
| Likewise, output pointers may be owning or non-owning. Unless otherwise | |
| documented, functions output non-owning pointers. The caller is not responsible | |
| for releasing the output pointer, but it must not use the pointer beyond its | |
| lifetime. The pointer may be released when the parent object is released or even | |
| sooner on state change in the parent object. | |
| If documented to output a *newly-allocated* object or a *reference* or *copy* of | |
| one, the caller is responsible for releasing the object when it is done. | |
| By convention, functions named `get0` return non-owning pointers. Functions | |
| named `new` or `get1` return owning pointers. Functions named `set0` or `add0` | |
| take ownership of arguments. Functions named `set1` or `add1` do not. They | |
| typically take a reference or make a copy internally. These names originally | |
| referred to the effect on a reference count, but the convention applies equally | |
| to non-reference-counted types. | |
| API documentation may also describe more complex obligations. For instance, an | |
| object may borrow a pointer for longer than the duration of a single function | |
| call, in which case the caller must ensure the lifetime extends accordingly. | |
| Memory errors are one of the most common and dangerous bugs in C and C++, so | |
| callers are encouraged to make use of tools such as | |
| [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) and | |
| higher-level languages. | |
| ## Thread safety | |
| BoringSSL is internally aware of the platform threading library and calls into | |
| it as needed. Consult the API documentation for the threading guarantees of | |
| particular objects. In general, stateless reference-counted objects like `RSA` | |
| or `EVP_PKEY` which represent keys may typically be used from multiple threads | |
| simultaneously, provided no thread mutates the key. | |
| ## Callbacks and Closures | |
| Several BoringSSL APIs, particularly in libssl, allow applications to configure | |
| callbacks to customize behavior. Often, an application may wish to pass in some | |
| [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)), where | |
| the callback is bound to some additional state. For example, a callback for TLS | |
| private key offload may need a handle to the application-specific private key. | |
| BoringSSL's APIs are C-based and use C function pointers, which do not support | |
| bound variables. Instead, C callback APIs split the closure into a function | |
| pointer and some `void *` data parameter. This is sometimes called "arg", | |
| "callback data", "context", "data", or "user data". | |
| For example, the `SSL_CTX_set_cert_cb` function takes an `arg` parameter, which | |
| is passed back into the user-supplied callback, `cb`. The user would pass a | |
| function that casts `arg` back to the expected type and looks up bound data as | |
| needed: | |
| ``` | |
| OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx, | |
| int (*cb)(SSL *ssl, void *arg), | |
| void *arg); | |
| ``` | |
| An application might use it with a C++ `std::function` as follows: | |
| ``` | |
| int RunCertCallback(SSL *ssl, void *arg) { | |
| auto *f = static_cast<std::function<int(SSL*)>*>(arg); | |
| return (*f)(ssl); | |
| } | |
| std::function<int(SSL*)> cert_cb = ...; | |
| SSL_CTX_set_cert_cb(ctx, RunCertCallback, &cert_cb); | |
| ``` | |
| Note that such an application would additionally need to ensure that `cert_cb` | |
| outlives `ctx`, e.g. by storing it in the `SSL_CTX`'s owning object. | |
| BoringSSL APIs, however, commonly take callbacks without an explicit data | |
| parameter. For example, the `SSL_set_custom_verify` takes an undecorated | |
| `callback` parameter: | |
| ``` | |
| OPENSSL_EXPORT void SSL_set_custom_verify( | |
| SSL *ssl, int mode, | |
| enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)); | |
| ``` | |
| In such APIs, the callback is expected to look up data through the owning | |
| object, here the `ssl`. Many types in BoringSSL, including `SSL`, support | |
| `ex_data`. `ex_data` lets applications associate extra data with the object. See | |
| the [API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ex_data.h.html) | |
| for more details. `ex_data` also supports registering a `free_func` callback, | |
| which can give the application more options to ensure callback data outlives the | |
| object. | |
| Often, for a callback-heavy object like `SSL`, the application will already have | |
| some owning object that wraps the `SSL`. The application can then register a | |
| single `ex_data` index, pointering back to the owning object, and store all the | |
| callback state there. | |
| For example, this code snippet connects `SSL` callbacks to methods on some | |
| wrapper `MySSLConnection` class. | |
| ``` | |
| class MySSLConnection { | |
| private: | |
| void Init() { | |
| ssl_.reset(SSL_new(...)); | |
| // Save a pointer in `ssl_` back to `this`. `this` owns and thus outlives | |
| // `ssl_`. (To have `ssl_` own its ex_data, use `SSL_get_ex_new_index`'s | |
| // `free_func` parameter.) | |
| CHECK(SSL_set_ex_data(ssl_.get(), ExDataIndex(), this)); | |
| // Register callbacks. | |
| SSL_set_custom_verify(ssl_.get(), SSL_VERIFY_PEER, | |
| &MySSLConnection::DoVerifyCallback); | |
| SSL_set_info_callback(ssl_.get(), &MySSLConnection::DoInfoCallback); | |
| ... | |
| } | |
| static int ExDataIndex() { | |
| static const int kIndex = [] { | |
| int idx = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr); | |
| CHECK(idx >= 0); | |
| return idx; | |
| }(); | |
| return kIndex; | |
| } | |
| static MySSLConnection *FromSSL(const SSL *ssl) { | |
| return static_cast<MySSLConnection*>( | |
| SSL_get_ex_data(ssl_.get(), ExDataIndex())); | |
| } | |
| // Callback functions passed to BoringSSL: | |
| static ssl_verify_result_t DoVerifyCallback(SSL *ssl, uint8_t *out_alert)) { | |
| return FromSSL(ssl)->Verify(out_alert); | |
| } | |
| static void DoInfoCallback(const SSL *ssl, int type, int value) { | |
| return FromSSL(ssl)->InfoCallback(type, value); | |
| } | |
| // The underlying methods that the callback functions forward to: | |
| ssl_verify_result_t VerifyCallback(uint8_t *out_alert)) { ... } | |
| void InfoCallback(int type, int value) { ... } | |
| bssl::UniquePtr<SSL> ssl_; | |
| }; | |
| ``` | |
| In other cases, the callback may live on a different object than is passed into | |
| the callback. The application can then use ex_data on either the passed-in | |
| object, or follow accessors to parent objects. For example, an `SSL_get_SSL_CTX` | |
| returns the `SSL_CTX` of an `SSL` and | |
| [`SSL_CTX_set_cert_verify_callback`'s documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_verify_callback) | |
| mentions that `SSL_get_ex_data_X509_STORE_CTX_idx` may be used to find the `SSL` | |
| corresponding to the `X509_STORE_CTX`. | |
| ``` | |
| OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb( | |
| SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *session)); | |
| OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( | |
| SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg), | |
| void *arg); | |
| ``` | |
| ## Contexts | |
| Many types in BoringSSL are named like `FOO_CTX`, where `CTX` is an abbrevation | |
| for "context". `FOO_CTX` is some object that is related to `FOO`. Due to the | |
| history of API names in OpenSSL, the relationship between the two can depend on | |
| context. | |
| Sometimes, `FOO` is a long-lived object and `FOO_CTX` is an individual operation | |
| on that object. For example: | |
| * An `EVP_MD` is a hash algorithm ("Message Digest"). An `EVP_MD_CTX` for some | |
| `EVP_MD` is single streaming hash operation that can accept data. | |
| * An `EVP_AEAD` is an AEAD algorithm. An `EVP_AEAD_CTX` for some `EVP_AEAD` is | |
| an AEAD key that can be used to encrypt or decrypt. | |
| * An `EVP_PKEY` is a public or private key. An `EVP_PKEY_CTX` for some | |
| `EVP_PKEY` is single signing, verifying, etc., operation on that key. | |
| * An `X509_STORE` carries trusted root certificates, etc., for verifying X.509 | |
| certificates. An `X509_STORE_CTX` is a single verification operation. | |
| In this case, the operation object may be a separate object, rather than a | |
| single-shot function, to allow the caller to configure extra parameters (similar | |
| to [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern)) or perform | |
| a multi-step, streaming operation. | |
| In other cases, the context object is the broader-scoped one: | |
| * An `SSL_CTX` is shared configuration and state between TLS/DTLS connections. | |
| An `SSL` is a single TLS/DTLS connection. | |
| * A `BIGNUM` is a big integer. A `BN_CTX` is a pool for reusing `BIGNUM` | |
| allocations. | |
| * An `X509V3_CTX` contains additional parameters for the legacy string-based | |
| X.509 extension API. (Do not use this API.) | |
| Consult the documentation if unsure which case a given pair of types falls into. |