summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-01-18 20:59:56 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-01-21 12:11:30 +0100
commit2c2ce24b4eb02beae3365a705a7db49636711241 (patch)
tree931640741372d6c411bac98db85cdd0f49751ae7 /openpgp-ffi
parent0572b8545e9ee92e41e56f36cbe1aaf8129fa2d3 (diff)
openpgp-ffi: Improve documentation.
- Prepend the documentation for the openpgp crate as introduction. - Explain how to read the documentation, examples, Rust types. - Explain the FFI contract.
Diffstat (limited to 'openpgp-ffi')
-rw-r--r--openpgp-ffi/src/lib.rs303
1 files changed, 253 insertions, 50 deletions
diff --git a/openpgp-ffi/src/lib.rs b/openpgp-ffi/src/lib.rs
index a40c64a2..92f546f5 100644
--- a/openpgp-ffi/src/lib.rs
+++ b/openpgp-ffi/src/lib.rs
@@ -1,62 +1,234 @@
-//! Provides a Foreign Function Interface.
+//! OpenPGP data types and associated machinery for C.
+//!
+//! This crate aims to provide a complete implementation of OpenPGP as
+//! defined by [RFC 4880] as well as several extensions (e.g., [RFC
+//! 6637], which describes ECC cryptography for OpenPGP, and [RFC
+//! 4880bis], the draft of the next OpenPGP standard). This includes
+//! support for unbuffered message processing.
+//!
+//! A few features that the OpenPGP community considers to be
+//! deprecated (e.g., version 3 compatibility) have been left out as
+//! well as support for functionality that we consider to be not only
+//! completely useless, but also dangerous (e.g., support for
+//! [unhashed signature subpackets]). We have also updated some
+//! OpenPGP defaults to avoid foot guns (e.g., this crate does not
+//! fallback to IDEA, but instead assumes all OpenPGP implementations
+//! understand AES). If some functionality is missing, please file a
+//! bug report.
+//!
+//! A non-goal of this crate is support for any sort of high-level,
+//! bolted-on functionality. For instance, [RFC 4880] does not define
+//! trust models, such as the web of trust, direct trust, or TOFU.
+//! Neither does this crate. [RFC 4880] does provide some mechanisms
+//! for creating trust models (specifically, UserID certifications),
+//! and this crate does expose those mechanisms.
+//!
+//! We also try hard to avoid dictating how OpenPGP should be used.
+//! This doesn't mean that we don't have opinions about how OpenPGP
+//! should be used in a number of common scenarios (for instance,
+//! message validation). But, in this crate, we refrain from
+//! expressing those opinions; we expose an opinionated, high-level
+//! interface in the [sequoia-core] and related crates. In our
+//! opinion, you should generally use those crates instead of this
+//! one.
+//!
+//! [RFC 4880]: https://tools.ietf.org/html/rfc4880
+//! [RFC 6637]: https://tools.ietf.org/html/rfc6637
+//! [RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05
+//! [unhashed signature subpackets]: https://tools.ietf.org/html/rfc4880#section-5.2.3.2
+//! [sequoia-core]: ../sequoia_core
+//!
+//!
+//! # Dear user,
+//!
+//! this library is written in Rust. Its expressive type system helps
+//! to prevent many classes of bugs, but it is also very demanding.
+//! For example, the infamous borrow checker, feared by those who dare
+//! to approach Rust, allows us to safely use shared resources. If
+//! you want to use this library, we need you to follow a set of
+//! rules, and you don't have the borrow checker to double check.
//!
//! We provide a set of functions that use C types and the C calling
//! convention. This interfaces allows you to use Sequoia safely from
-//! any other language.
+//! any other language, provided that you follow [The Rules].
//!
-//! # Guarantees
+//! If you don't follow [The Rules], we will terminate the process.
+//! That is not meant as a threat, of course. But, as in C, passing a
+//! bad pointer to a function is undefined behavior in Rust.
+//! Therefore, passing a bad pointer to a function in this crate is
+//! undefined behavior as well. We try to mitigate this problem by
+//! trying to detect undefined behavior resulting from not following
+//! [The Rules] by printing assertion failures on stderr, and
+//! terminating the process.
//!
-//! Provided that the caller obeys her side of the contract, this
-//! library...
+//! In return for following [The Rules], you can enjoy the reliability
+//! that Rust's type system brings this library. For example, the
+//! robust tracking of ownership ensures that we will not leak memory.
//!
-//! - will not make an invalid memory access,
-//! - will not `abort(2)`,
-//! - XXX
+//! The C API is documented here. We invite you to visit the
+//! documentation of the [corresponding Rust crate], the structure
+//! closely resembles this crate.
//!
-//! # Types
+//! [The Rules]: #the-rules
+//! [corresponding Rust crate]: ../sequoia_openpgp/index.html
+//!
+//!
+//! # Examples
+//!
+//! This documentation contains examples in the style of Rust
+//! examples. For short examples, we will omit the main function.
+//! For example:
+//!
+//! ```c
+//! #include <sequoia/openpgp.h>
+//! #include <error.h>
+//!
+//! pgp_error_t err;
+//! pgp_tpk_t tpk = pgp_tpk_from_file (&err, "../openpgp/tests/data/keys/testy.pgp");
+//! if (tpk == NULL)
+//! error (1, 0, "pgp_tpk_from_file: %s", pgp_error_string (err));
+//!
+//! /* XXX: Do something interesting. */
+//!
+//! pgp_tpk_free (tpk);
+//! ```
+//!
+//! The examples are compiled and executed as part of the test suite,
+//! and they will free all objects that are created.
+//!
+//!
+//! # The Rules
+//!
+//! These rules must be followed. Failure to follow these rules
+//! results in problems like memory leaks, undefined behavior, or
+//! process termination. This is also a guide on how to read the
+//! documentation for this library.
+//!
+//! ## Undefined Behavior
+//!
+//! Undefined behavior means that the state of the library is
+//! inconsistent, and the resulting behavior is unpredictable. It
+//! often leads to security problems, like information exfiltration,
+//! or code execution.
+//!
+//! Undefined behavior may be the result of a bug in this library, or
+//! due to failure to comply to [The Rules]. Furthermore, memory
+//! exhaustion may lead to undefined behavior.
+//!
+//! This library tries to detect cases of undefined behavior, and
+//! *abort(3)* the process. This fail-fast policy helps to protect
+//! against exfiltration and code execution attacks, and should
+//! clearly highlight either a bug in this library (please get in
+//! contact!), or a bug in your code.
+//!
+//! ## Error handling
+//!
+//! Errors happen and must be handled by the caller. There are
+//! functions that cannot fail, functions that may fail, and functions
+//! that may fail and communicate a complex error value to the caller.
+//!
+//! Functions that cannot fail are a nice consequence of the
+//! 'fail-fast on undefined behavior'-rule. An example of such
+//! function is [`pgp_fingerprint_to_string`]. This function cannot
+//! fail, unless either the given fingerprint reference is not valid,
+//! or the allocation for the string failed, which is considered
+//! undefined behavior.
+//!
+//! [`pgp_fingerprint_to_string`]: fingerprint/fn.pgp_fingerprint_to_string.html
+//!
+//! Failing functions signal failure either in-band (e.g. `NULL`, or
+//! -1), using `pgp_status_t`, and may store complex error information
+//! in a caller-provided location. For example, constructors often
+//! return `NULL` to signal errors. An example of a constructor that
+//! may fail and return `NULL`, but does not communicate complex error
+//! is [`pgp_fingerprint_from_hex`]. [`pgp_packet_parser_from_bytes`],
+//! on the other hand, will return `NULL` and store a complex error at
+//! the location given using the `errp` parameter.
+//!
+//! [`pgp_fingerprint_from_hex`]: fingerprint/fn.pgp_fingerprint_from_hex.html
+//! [`pgp_packet_parser_from_bytes`]: parse/fn.pgp_packet_parser_from_bytes.html
+//!
+//! Errors may be inspected using [`pgp_error_status`], and formatted
+//! as error message using [`pgp_error_string`]. Errors must be freed
+//! using [`pgp_error_free`].
+//!
+//! [`pgp_error_status`]: error/fn.pgp_error_status.html
+//! [`pgp_error_string`]: error/fn.pgp_error_string.html
+//! [`pgp_error_free`]: error/fn.pgp_error_free.html
+//!
+//! ## Types
+//!
+//! When we interact across the FFI boundary between C and Rust, we
+//! need to talk about the types used to interchange data. The types
+//! follow different rules.
+//!
+//! ### Objects
//!
//! Sequoia objects are opaque objects. They are created in
-//! constructors, and must be freed when no longer needed.
+//! constructors, and must be freed when no longer needed. Failure to
+//! free an object results in a memory leak.
//!
-//! Pointers handed to Sequoia must not be `NULL`, unless explicitly
-//! stated. See [references].
+//! A typical example of creating an object, using it, and
+//! deallocating it is the following. We will [parse a fingerprint]
+//! from a hexadecimal number, and then [pretty-print] it for user
+//! consumption:
//!
-//! [references]: #references
+//! [parse a fingerprint]: fingerprint/fn.pgp_fingerprint_from_hex.html
+//! [pretty-print]: fingerprint/fn.pgp_fingerprint_to_string.html
//!
-//! Enumeration-like values must be in the valid range.
+//! ```c
+//! #include <assert.h>
+//! #include <stdlib.h>
+//! #include <string.h>
+//! #include <sequoia/openpgp.h>
//!
-//! Strings must be UTF-8 encoded and zero-terminated. Malformed
-//! characters will be substituted, and the result is likely not what
-//! you expect.
+//! pgp_fingerprint_t fp =
+//! pgp_fingerprint_from_hex ("D2F2C5D45BE9FDE6A4EE0AAF31855247603831FD");
//!
-//! # Ownership
+//! char *pretty = pgp_fingerprint_to_string (fp);
+//! assert (strcmp (pretty,
+//! "D2F2 C5D4 5BE9 FDE6 A4EE 0AAF 3185 5247 6038 31FD") == 0);
//!
-//! When ownership of a `T` is transferred across the FFI boundary, a
-//! `*mut T` is used.
+//! free (pretty);
+//! pgp_fingerprint_free (fp);
+//! ```
//!
-//! To transfer ownership from Rust to C, we box the Rust object, and
-//! use [`Box::into_raw(..)`]. From this moment on, ownership must be
-//! managed by the C application.
+//! After use, the fingerprint object must be deallocated. Note that
+//! objects may reference other objects, so a good practice is to
+//! deallocate the objects in the reverse order they were created in.
//!
-//! [`Box::into_raw(..)`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw
+//! #### Ownership
//!
-//! To transfer ownership from C to Rust, we re-create the box using
-//! [`Box::from_raw(..)`].
+//! In Rust, every value is owned. It may reside on the stack, the
+//! heap, or be embedded in a struct or enum. If you take ownership
+//! of an object, e.g. by using some constructor, it is your
+//! responsibility to manage its lifetime. The most common way to
+//! transfer ownership back to Rust is to deallocate the object.
+//! Failure to deallocate the object leads to a memory leak.
//!
-//! [`Box::from_raw(..)`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.from_raw
+//! Looking at the Rust functions in this library, when ownership of a
+//! `T` is transferred across the FFI boundary, a `*mut T` is used.
//!
//! In this crate we use a series of macros to transfer ownership from
-//! Rust to C. `fry_box` matches on `Result<T>`, handling errors by
-//! terminating the current function, returning the error using the
-//! context. `maybe_box_raw` matches on `Option<T>`, turning `None`
-//! into `NULL`. Finally, `box_raw` is merely a shortcut for
+//! Rust to C. `ffi_try_box` matches on `Result<T>`, handling errors
+//! by terminating the current function returning the error.
+//! `maybe_box_raw` matches on `Option<T>`, turning `None` into
+//! `NULL`. Finally, `box_raw` is merely a shortcut for
//! `Box::into_raw(Box::new(..))`.
//!
-//! # References
+//! ### References
+//!
+//! All references transferred across the FFI boundary must be valid,
+//! and point to live objects constructed using constructors of this
+//! library. Using references constructed in any other way results in
+//! undefined behavior.
//!
-//! When references are transferred across the FFI boundary, we use
-//! `*const T`, or `*mut T`. If the parameter is optional, a
-//! `Option<&T>` or `Option<&mut T>` is used.
+//! In some places, references handed to, or returned from this
+//! library may be `NULL`. This is the exception rather than the
+//! rule. If you look at a functions Rust signature, a `Option<&T>`
+//! or `Option<&mut T>` is used for arguments or results that may be
+//! NULL. On the other hand, function arguments that are not optional
+//! use `*const T`, or `*mut T`.
//!
//! Application code must adhere to Rust's reference rules:
//!
@@ -69,40 +241,71 @@
//! function uses `Option<&T>` or `Option<&mut T>`, it may be called
//! with `NULL`. A notable example are the destructors (`sq_*_free`).
//!
-//! # Lifetimes
+//! ### Lifetimes
//!
//! If you derive a complex object from another complex object, you
//! must assume that the original object is borrowed by the resulting
//! object unless explicitly stated otherwise. For example, objects
//! created using a context must not outlive that context. Similarly,
-//! iterators must not outlive the object they are created from.
+//! iterators must not outlive the object they are created from. It
+//! is a good practice is to deallocate the objects in the reverse
+//! order they were created in.
//!
//! Failing to adhere to lifetime restrictions results in undefined
//! behavior.
//!
-//! # Error handling
+//! ### Strings
+//!
+//! Strings given to this library must be UTF-8 encoded and
+//! zero-terminated. Malformed characters will be substituted.
//!
-//! Sequoia will panic if you provide bad arguments, e.g. hand a
-//! `NULL` pointer to a function that does not explicitly allow this.
+//! Strings produced by this library will be UTF-8 encoded and
+//! zero-terminated. Malformed characters will be substituted. They
+//! will be allocated using *malloc(3)* und must be *free(3)* d. A
+//! few functions in this library may return a `const char *`, which
+//! must not be freed, of course.
//!
-//! Failing functions return `NULL`. Functions that require a
-//! `Context` return complex errors. Complex errors are stored in the
-//! `Context`, and can be retrieved using `sq_last_strerror`.
+//! ### Enumerations
//!
-//! # Example
+//! Values must be constructed using the symbols or macros defined by
+//! this library. Using values constructed in any other way is
+//! undefined behavior.
+//!
+//! In the following example, we will decode an armored blob in
+//! memory. Note how we use `PGP_ARMOR_KIND_ANY` in the [constructor]
+//! of the armor reader to indicate that we will consume any kind of
+//! data, and later use `PGP_ARMOR_KIND_FILE` to check what we got in
+//! the end.
+//!
+//! [constructor]: armor/fn.pgp_armor_reader_from_bytes.html
//!
//! ```c
-//! #include <sequoia/openpgp.h>
+//! #include <assert.h>
//! #include <error.h>
+//! #include <stdlib.h>
+//! #include <stdio.h>
+//! #include <string.h>
+//! #include <sequoia/openpgp.h>
+//!
+//! const char *armored =
+//! "-----BEGIN PGP ARMORED FILE-----\n"
+//! "\n"
+//! "SGVsbG8gd29ybGQh\n"
+//! "=s4Gu\n"
+//! "-----END PGP ARMORED FILE-----\n";
+//!
+//! pgp_reader_t armor =
+//! pgp_armor_reader_from_bytes (armored, strlen (armored), PGP_ARMOR_KIND_ANY);
//!
//! pgp_error_t err;
-//! pgp_tpk_t tpk;
+//! char message[12];
+//! if (pgp_reader_read (&err, armor, (uint8_t *) message, 12) != 12)
+//! error (1, 0, "Reading failed: %s", pgp_error_string (err));
//!
-//! tpk = pgp_tpk_from_file (&err, "../openpgp/tests/data/keys/testy.pgp");
-//! if (tpk == NULL)
-//! error (1, 0, "pgp_tpk_from_bytes: %s", pgp_error_string (err));
+//! assert (pgp_armor_reader_kind (armor) == PGP_ARMOR_KIND_FILE);
+//! assert (memcmp (message, "Hello world!", 12) == 0);
//!
-//! pgp_tpk_free (tpk);
+//! pgp_reader_free (armor);
//! ```
#![warn(missing_docs)]