|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- # 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.
-
-
- ## 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).
-
- Some headers lack documention comments. These are functions and structures from
- OpenSSL's legacy ASN.1, X.509, and PEM implementation. If possible, avoid using
- them. These are left largely unmodified from upstream and are retained only for
- compatibility with existing OpenSSL consumers.
-
-
- ## 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.
-
- 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 specific and may change over time.
-
-
- ## 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.
-
-
- ## 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 functioned 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`. Consumers are not required 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.)
-
-
- ### 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.
-
-
- ## 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.
|