• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# BoringSSL API Conventions
2
3This document describes conventions for BoringSSL APIs. The [style
4guide](./STYLE.md) also includes guidelines, but this document is targeted at
5both API consumers and developers. API documentation in BoringSSL may assume
6these conventions by default, rather than repeating them for every function.
7
8
9## Documentation
10
11All supported public APIs are documented in the public header files, found in
12`include/openssl`. The API documentation is also available
13[online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
14
15Experimental public APIs are found in `include/openssl/experimental`. Use of
16these will likely be incompatible with changes in the near future as they are
17finalized.
18
19## Forward declarations
20
21Do not write `typedef struct foo_st FOO` or try otherwise to define BoringSSL's
22types. Including `openssl/base.h` (or `openssl/ossl_typ.h` for consumers who
23wish to be OpenSSL-compatible) will forward-declare each type without importing
24the rest of the library or invasive macros.
25
26
27## Error-handling
28
29Most functions in BoringSSL may fail, either due to allocation failures or input
30errors. Functions which return an `int` typically return one on success and zero
31on failure. Functions which return a pointer typically return `NULL` on failure.
32However, due to legacy constraints, some functions are more complex. Consult the
33API documentation before using a function.
34
35On error, most functions also push errors on the error queue, an `errno`-like
36mechanism. See the documentation for
37[err.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/err.h.html)
38for more details.
39
40As with `errno`, callers must test the function's return value, not the error
41queue to determine whether an operation failed. Some codepaths may not interact
42with the error queue, and the error queue may have state from a previous failed
43operation. After checking for failure, the caller can then inspect the error
44queue in the failure case for details.
45
46As a notable exception, some functions in the SSL/TLS library use a multi-step
47process to indicate failure: First, the return value indicates whether the
48operation failed. Then, `SSL_get_error` indicates whether the failure was due to
49an error (`SSL_ERROR_SSL`) or some recoverable condition (e.g.
50`SSL_ERROR_WANT_READ`). In the former case, the caller can use the error queue
51for more information.
52
53When ignoring a failed operation, it is recommended to call `ERR_clear_error` to
54avoid the state interacting with future operations. Failing to do so should not
55affect the actual behavior of any functions, but may result in errors from both
56operations being mixed in error logging. We hope to
57[improve](https://bugs.chromium.org/p/boringssl/issues/detail?id=38) this
58situation in the future.
59
60Where possible, avoid conditioning on specific reason codes and limit usage to
61logging. The reason codes are very fine-grained and tend to leak details of the
62library's internal structure. Changes in the library often have a side effect of
63changing the exact reason code returned.
64
65
66## Memory allocation
67
68BoringSSL allocates memory via `OPENSSL_malloc`, found in `mem.h`. Use
69`OPENSSL_free`, found in the same header file, to release it. BoringSSL
70functions will fail gracefully on allocation error, but it is recommended to use
71a `malloc` implementation that `abort`s on failure.
72
73
74## Pointers and slices
75
76Unless otherwise specified, pointer parameters that refer to a single object,
77either as an input or output parameter, may not be `NULL`. In this case,
78BoringSSL often will not check for `NULL` before dereferencing, so passing
79`NULL` may crash or exhibit other undefined behavior. (Sometimes the function
80will check for `NULL` anyway, for OpenSSL compatibility, but we still consider
81passing `NULL` to be a caller error.)
82
83Pointer parameters may also refer to a contiguous sequence of objects, sometimes
84referred to as a *slice*. These will typically be a pair of pointer and length
85parameters named like `plaintext` and `plaintext_len`, or `objs` and `num_objs`.
86We prefer the former for byte buffers and the latter for sequences of other
87types. The documentation will usually refer to both parameters together, e.g.
88"`EVP_DigestUpdate` hashes `len` bytes from `data`."
89
90Parameters in C and C++ that use array syntax, such as
91`uint8_t out[SHA256_DIGEST_LENGTH]`, are really pointers. In BoringSSL's uses of
92this syntax, the pointer must point to the specified number of values.
93
94In other cases, the documentation will describe how the function parameters
95determine the slice's length. For example, a slice's length may be measured in
96units other than element count, multiple slice parameters may share a length, or
97a slice's length may be implicitly determined by other means like RSA key size.
98
99By default, BoringSSL follows C++'s
100[slice conventions](https://davidben.net/2024/01/15/empty-slices.html)
101for pointers. That is, unless otherwise specified, pointers for non-empty
102(non-zero length) slices must be represented by a valid pointer to that many
103objects in memory. Pointers for empty (zero length) slices must either be `NULL`
104or point within some sequence of objects of a compatible type.
105
106WARNING: The dangling, non-null pointer used by Rust empty slices may *not* be
107passed into BoringSSL. Rust FFIs must adjust such pointers to before passing to
108BoringSSL. For example, see the `FfiSlice` abstraction in `bssl-crypto`. (We may
109relax this if pointer arithmetic rules in C/C++ are adjusted to permit Rust's
110pointers. Until then, it is impractical for a C/C++ library to act on such a
111slice representation. See
112[this document](https://davidben.net/2024/01/15/empty-slices.html) for more
113discussion.)
114
115In some cases, OpenSSL compatibility requires that a function will treat `NULL`
116slice pointers differently from non-`NULL` pointers. Such behavior will be
117described in documentation. For examples, see `EVP_EncryptUpdate`,
118`EVP_DigestSignFinal`, and `HMAC_Init_ex`. Callers passing potentially empty
119slices into such functions should take care that the `NULL` case is either
120unreachable or still has the desired behavior.
121
122If a `const char *` parameter is described as a "NUL-terminated string" or a
123"C string", it must point to a sequence of `char` values containing a NUL (zero)
124value, which determines the length. Unless otherwise specified, the pointer may
125not be `NULL`, matching the C standard library.
126
127For purposes of C and C++'s
128[strict aliasing](https://en.cppreference.com/w/c/language/object#Strict_aliasing)
129requirements, objects passed by pointers must be accessible as the specified
130type. `uint8_t` may be assumed to be the same type as `unsigned char` and thus
131may be the pointer type for all object types. BoringSSL does not support
132platforms where `uint8_t` is a non-character type. However, there is no
133strict aliasing sanitizer, very few C and C++ codebases are valid by strict
134aliasing, and BoringSSL itself has some
135[known strict aliasing bugs](https://crbug.com/boringssl/444), thus we strongly
136recommend consumers build with `-fno-strict-aliasing`.
137
138Pointer parameters additionally have ownership and lifetime requirements,
139discussed in the section below.
140
141
142## Object initialization and cleanup
143
144BoringSSL defines a number of structs for use in its APIs. It is a C library,
145so the caller is responsible for ensuring these structs are properly
146initialized and released. Consult the documentation for a module for the
147proper use of its types. Some general conventions are listed below.
148
149
150### Heap-allocated types
151
152Some types, such as `RSA`, are heap-allocated. All instances will be allocated
153and returned from BoringSSL's APIs. It is an error to instantiate a heap-
154allocated type on the stack or embedded within another object.
155
156Heap-allocated types may have functioned named like `RSA_new` which allocates a
157fresh blank `RSA`. Other functions may also return newly-allocated instances.
158For example, `RSA_parse_public_key` is documented to return a newly-allocated
159`RSA` object.
160
161Heap-allocated objects must be released by the corresponding free function,
162named like `RSA_free`. Like C's `free` and C++'s `delete`, all free functions
163internally check for `NULL`. It is redundant to check for `NULL` before calling.
164
165A heap-allocated type may be reference-counted. In this case, a function named
166like `RSA_up_ref` will be available to take an additional reference count. The
167free function must be called to decrement the reference count. It will only
168release resources when the final reference is released. For OpenSSL
169compatibility, these functions return `int`, but callers may assume they always
170successfully return one because reference counts use saturating arithmetic.
171
172C++ consumers are recommended to use `bssl::UniquePtr` to manage heap-allocated
173objects. `bssl::UniquePtr<T>`, like other types, is forward-declared in
174`openssl/base.h`. Code that needs access to the free functions, such as code
175which destroys a `bssl::UniquePtr`, must include the corresponding module's
176header. (This matches `std::unique_ptr`'s relationship with forward
177declarations.) Note, despite the name, `bssl::UniquePtr` is also used with
178reference-counted types. It owns a single reference to the object. To take an
179additional reference, use the `bssl::UpRef` function, which will return a
180separate `bssl::UniquePtr`.
181
182
183### Stack-allocated types
184
185Other types in BoringSSL are stack-allocated, such as `EVP_MD_CTX`. These
186types may be allocated on the stack or embedded within another object.
187However, they must still be initialized before use.
188
189Every stack-allocated object in BoringSSL has a *zero state*, analogous to
190initializing a pointer to `NULL`. In this state, the object may not be
191completely initialized, but it is safe to call cleanup functions. Entering the
192zero state cannot fail. (It is usually `memset(0)`.)
193
194The function to enter the zero state is named like `EVP_MD_CTX_init` or
195`CBB_zero` and will always return `void`. To release resources associated with
196the type, call the cleanup function, named like `EVP_MD_CTX_cleanup`. The
197cleanup function must be called on all codepaths, regardless of success or
198failure. For example:
199
200    uint8_t md[EVP_MAX_MD_SIZE];
201    unsigned md_len;
202    EVP_MD_CTX ctx;
203    EVP_MD_CTX_init(&ctx);  /* Enter the zero state. */
204    int ok = EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) &&
205             EVP_DigestUpdate(&ctx, "hello ", 6) &&
206             EVP_DigestUpdate(&ctx, "world", 5) &&
207             EVP_DigestFinal_ex(&ctx, md, &md_len);
208    EVP_MD_CTX_cleanup(&ctx);  /* Release |ctx|. */
209
210Note that `EVP_MD_CTX_cleanup` is called whether or not the `EVP_Digest*`
211operations succeeded. More complex C functions may use the `goto err` pattern:
212
213      int ret = 0;
214      EVP_MD_CTX ctx;
215      EVP_MD_CTX_init(&ctx);
216
217      if (!some_other_operation()) {
218        goto err;
219      }
220
221      uint8_t md[EVP_MAX_MD_SIZE];
222      unsigned md_len;
223      if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) ||
224          !EVP_DigestUpdate(&ctx, "hello ", 6) ||
225          !EVP_DigestUpdate(&ctx, "world", 5) ||
226          !EVP_DigestFinal_ex(&ctx, md, &md_len) {
227        goto err;
228      }
229
230      ret = 1;
231
232    err:
233      EVP_MD_CTX_cleanup(&ctx);
234      return ret;
235
236Note that, because `ctx` is set to the zero state before any failures,
237`EVP_MD_CTX_cleanup` is safe to call even if the first operation fails before
238`EVP_DigestInit_ex`. However, it would be illegal to move the `EVP_MD_CTX_init`
239below the `some_other_operation` call.
240
241As a rule of thumb, enter the zero state of stack-allocated structs in the
242same place they are declared.
243
244C++ consumers are recommended to use the wrappers named like
245`bssl::ScopedEVP_MD_CTX`, defined in the corresponding module's header. These
246wrappers are automatically initialized to the zero state and are automatically
247cleaned up.
248
249
250### Data-only types
251
252A few types, such as `SHA_CTX`, are data-only types and do not require cleanup.
253These are usually for low-level cryptographic operations. These types may be
254used freely without special cleanup conventions.
255
256
257### Ownership and lifetime
258
259When working with allocated objects, it is important to think about *ownership*
260of each object, or what code is responsible for releasing it. This matches the
261corresponding notion in higher-level languages like C++ and Rust.
262
263Ownership applies to both uniquely-owned types and reference-counted types. For
264the latter, ownership means the code is responsible for releasing one
265reference. Note a *reference* in BoringSSL refers to an increment (and eventual
266decrement) of an object's reference count, not `T&` in C++. Thus, to "take a
267reference" means to increment the reference count and take ownership of
268decrementing it.
269
270As BoringSSL's APIs are primarily in C, ownership and lifetime obligations are
271not rigorously annotated in the type signatures or checked at compile-time.
272Instead, they are described in
273[API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
274This section describes some conventions.
275
276Unless otherwise documented, functions do not take ownership of pointer
277arguments. The pointer typically must remain valid for the duration of the
278function call. The function may internally copy information from the argument or
279take a reference, but the caller is free to release its copy or reference at any
280point after the call completes.
281
282A function may instead be documented to *take* or *transfer* ownership of a
283pointer. The caller must own the object before the function call and, after
284transfer, no longer owns it. As a corollary, the caller may no longer reference
285the object without a separate guarantee on the lifetime. The function may even
286release the object before returning. Callers that wish to independently retain a
287transfered object must therefore take a reference or make a copy before
288transferring. Callers should also take note of whether the function is
289documented to transfer pointers unconditionally or only on success. Unlike C++
290and Rust, functions in BoringSSL typically only transfer on success.
291
292Likewise, output pointers may be owning or non-owning. Unless otherwise
293documented, functions output non-owning pointers. The caller is not responsible
294for releasing the output pointer, but it must not use the pointer beyond its
295lifetime. The pointer may be released when the parent object is released or even
296sooner on state change in the parent object.
297
298If documented to output a *newly-allocated* object or a *reference* or *copy* of
299one, the caller is responsible for releasing the object when it is done.
300
301By convention, functions named `get0` return non-owning pointers. Functions
302named `new` or `get1` return owning pointers. Functions named `set0` take
303ownership of arguments. Functions named `set1` do not. They typically take a
304reference or make a copy internally. These names originally referred to the
305effect on a reference count, but the convention applies equally to
306non-reference-counted types.
307
308API documentation may also describe more complex obligations. For instance, an
309object may borrow a pointer for longer than the duration of a single function
310call, in which case the caller must ensure the lifetime extends accordingly.
311
312Memory errors are one of the most common and dangerous bugs in C and C++, so
313callers are encouraged to make use of tools such as
314[AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) and
315higher-level languages.
316
317
318## Thread safety
319
320BoringSSL is internally aware of the platform threading library and calls into
321it as needed. Consult the API documentation for the threading guarantees of
322particular objects. In general, stateless reference-counted objects like `RSA`
323or `EVP_PKEY` which represent keys may typically be used from multiple threads
324simultaneously, provided no thread mutates the key.
325