git clone --recursive https://fuchsia.googlesource.com/mundane
Development occurs at https://fuchsia.googlesource.com/mundane, with the GitHub repository as a read-only mirror. See Code reviews for details on how to submit changes.
Mundane depends on BoringSSL, which is in a Git submodule. When cloning this
repository, make sure to pass the --recursive
flag to Git to also download
this submodule.
unsafe
is not allowed, except for in the boringssl
module. We
#[forbid(unsafe)]
in all other modules, so code that uses unsafe
outside of
that module should fail to compile. For details on how to use unsafe
in the
boringssl
module, see the doc comment on that module.
The #[must_use]
directive causes the compiler to emit a warning if code calls
a function but does not use its return value. It is a very useful lint against
failing to properly act on the result of cryptographic operations. A
#[must_use]
directive should go on:
- All functions/methods (including in trait definitions) which return a value and are visible outside of the crate
- In the
boringssl
module:- All functions/methods (including in trait definitions) which return a value
and are visible outside of the
boringssl
module or are exported from theraw
orwrapper
modules to the top-levelboringssl
module
- All functions/methods (including in trait definitions) which return a value
and are visible outside of the
#[must_use]
may also be used on types, but should be evaluated on a
case-by-case basis. A few things to keep in mind:
- All functions defined in Mundane which return values have
#[must_use]
on them, so the case of a type returned by a function defined in Mundane is already covered. - Unlike on functions,
#[must_use]
on types affects code other than the immediate caller since code outside of this crate may return types which are defined in this crate.
Thus, #[must_use]
should only be used on a type when it's desired for
functions defined outside of this crate which return the type to have
#[must_use]
behavior.
As a general rule of thumb, this should be restricted to types which could be
used to make security decisions. For example, digests and signatures should have
#[must_use]
, while keys should not have it.
TODO(joshlf): Re-evaluate this policy? Maybe we want to put #[must_use]
on
more types?
Some clients require access to insecure operations in order to interoperate with legacy applications. While we provide these operations, we do so with a few caveats:
- We only provide the bare minimum required. For example, while we provide HMAC-SHA1, we do not provide SHA-1 on its own, as it is not needed.
- We attempt to make it as difficult as possible for somebody to use an insecure operation unintentionally, as detailed in the next section.
We use a number of mechanisms to make it less likely for somebody to use an insecure operation unintentionally or without understanding the implications. They are:
- Use of Rust's
#[deprecated]
attribute so that code which uses insecure operations will produce a compiler warning - Naming of insecure types, functions, and methods with an "insecure" prefix so that their use will stand out in code, and their insecurity will stand out when reading their documentation
- Documentation comments that stress the operation's insecurity
- Placing all insecure operations in their own
insecure
module so that users are unlikely to accidentally come across an insecure operation while browsing other documentation - Placing the
insecure
module behind a feature flag which is disabled by default
The whole is also more than the sum of the parts. Taken together, these mechanisms serve to give an appropriate air of gravitas to insecure operations. Users should feel uneasy - like they're wading into dangerous and subtle territory (because they are!). They should be made to feel the gravity of the situation, and to appreciate the importance of carefully considering whether using an insecure operation is appropriate.
Rust provides the #[deprecated]
attribute which can be
placed on items including modules, types, functions, methods, and traits. If a
deprecated item is imported or used, it will cause a compiler warning (two,
actually - one for the import, and one for the use in code).
In Mundane, all insecure operations must be marked with a #[deprecated]
attribute with an appropriate message. This includes all items that a user could
ever interact with - types, functions, methods, etc. If it has a pub
in front
of it, it needs a deprecation attribute. For example:
#[deprecated(note = "Foo is considered insecure")]
pub struct InsecureFooResult;
impl InsecureFooResult {
#[deprecated(note = "Foo is considered insecure")]
pub fn insecure_frobnicate(&self) { ... }
}
#[deprecated(note = "Foo is considered insecure")]
pub fn insecure_foo() -> InsecureFooResult { ... }
Every user-facing Rust item associated with an insecure operation carries an
"insecure" prefix on its name. For types and traits, this is of the form
Insecure
, while for functions, methods, and modules, it's of the form
insecure_
. See the example from the previous section for a demonstration of
this naming.
The justification for this is twofold. First, it makes it so that, while reading documentation, it's unlikely for even a casual reader to miss that what they're reading about is a special case that should be carefully considered. Second, it makes it very obvious when reading or reviewing code that makes use of insecure operations.
Every documentation comment on an insecure operation should have the following structure:
/// INSECURE: <summary of operation>
///
/// # Security
///
/// <operation> is considered insecure, and should only be used for compatibility
/// with legacy applications.
///
/// <further documentation if necessary>
As with naming, this serves to lessen the likelihood that a user will use an insecure operation without realizing what they're doing.
All insecure operations are exposed through a top-level insecure
module, which
is itself marked with a deprecation attribute, and carries appropriate
module-level documentation.
Unfortunately, due to Rust's visibility rules, making this work involves a bit
of a dance. For reasons of practicality, insecure operations are defined
alongside their secure counterparts. For example, the InsecureHmacSha1
type is
defined in the hmac
module, and the InsecureSha1Digest
type is defined in
the hash
module. A programmer's first inclination might be to mark these as
pub(crate)
and attempt to re-export them from the insecure
module.
Unfortunately, Rust forbids this.
Instead, we take the somewhat circuitous approach of putting an insecure
operation inside of its own pub(crate)
module (e.g., hmac::insecure_hmac
).
Inside of this module, the insecure operation can be pub
rather than
pub(crate)
. This, in turn, allows the insecure
module to re-export the item
without running afoul of the compiler. It's an awkward dance, but it makes it so
that insecure operations can only be accessed through the insecure
module,
which is a big win.
By default, the insecure
module is not present. The user must explicitly
enable the insecure
feature in order to enable the module.
Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to https://cla.developers.google.com/ to see your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again.
All submissions, including submissions by project members, require review. We use Gerrit for this purpose.
If you have not done so on this machine, you will need to set up a password for Gerrit. Sign in with a Google account, visit this link, and click the "Generate Password" link in the top right. You will also need to prepare your checkout to add Change-Ids on commit. In the repository, run:
curl -Lo .git/hooks/commit-msg https://fuchsia-review.googlesource.com/tools/hooks/commit-msg
chmod u+x .git/hooks/commit-msg
To upload a change, push it to the special refs/for/master
target:
git push origin HEAD:refs/for/master
Alternatively, to configure the repository so that all pushes go to this target
(git push
on its becomes equivalent to the above):
git config remote.origin.push HEAD:refs/for/master
The output of git push
will then give you a link to the change. Add
joshlf@google.com
as a reviewer.
Pushing a commit with the same Change-Id as an existing change will upload a new
version of it. (Use the git rebase
or git commit --amend
commands.)
For more detailed instructions, see the Gerrit User Guide.
This project follows Google's Open Source Community Guidelines.