Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add artifact sign/verify via libsodium. #357

Merged
merged 7 commits into from
Apr 8, 2016
Merged

Conversation

bookshelfdave
Copy link
Contributor

This PR adds artifact sign/verify via libsodium.

The following subcommands have been implemented:

hab artifact sign
hab artifact verify
hab origin key generate

hab archive has been renamed to hab artifact.

Note, this does not implement user or service keys, and also excludes encryption/decryption. I'm going to leave some commented out code in (any code that includes "box"), please ignore for now and I'll update it when this story is completed next week.

1 minute tutorial

  1. Generate an origin key
./target/debug/hab origin key generate habitat
  1. Make a tarfile that you want to sign:
tar cvJf chef-zlib.-1.2.8-20160310193228.xz /opt/bldr/pkgs/chef/zlib/1.2.8/20160310193228/
  1. Create a signed artifact:
./target/debug/hab artifact sign chef-zlib.-1.2.8-20160310193228.xz chef-zlib.-1.2.8-20160310193228.hab --origin habitat

OR

export HABITAT_ORIGIN=habitat
./target/debug/hab artifact sign chef-zlib.-1.2.8-20160310193228.xz chef-zlib.-1.2.8-20160310193228.hab 
  1. Look at the header:
head -3 chef-zlib.-1.2.8-20160310193228.hab
  1. Skip verification and just access the tarball:
tail -n +4 chef-zlib.-1.2.8-20160310193228.hab | tar tvJ
  1. Verify the artifact and extract it's contents
./target/debug/hab artifact verify ./chef-zlib.-1.2.8-20160310193228.hab ./out.xz
  1. Make sure it worked:
tar tvJf out.xz

TODO:

  • tests
  • cleanup "find newest key code"
  • tz on revision string generation
  • don't output tar file on verify
  • honor HABITAT_ORIGIN
  • return a meaningful value out to the shell

Development notes

GPG still exists in the repo

I'll remove references to GPG in a later PR

sodiumoxide + libsodium-sys

While we are waiting for the generichash functions from this PR to be merged, we're pointing to a fork. The annoying thing about this is that we have to include the entire repo as a cargo override via components/.cargo/config and Cargo.toml . Once the PR is merged to the official repo, we can remove these files and continue in peace.

Compiling

In order to compile this today, you'll need the libsodium package installed and Rust needs to know how to link to libsodium via SODIUM_LIB_DIR.

export SODIUM_LIB_DIR=/opt/studios/src/opt/bldr/pkgs/chef/libsodium/1.0.8/20160406134120/lib
export LD_LIBRARY_PATH=${SODIUM_LIB_DIR}

I updated the depot and sup plans to include libsodium, but we'll need to address the plan that builds hab asap.


These are a prettier version of the docs I've embedded inside of hab_crypto.rs:

Habitat uses libsodium and it's Rust counterpart sodiumoxide for cryptographic operations.

Concepts and terminology:

  • All public keys/certificates/signatures will be referred to as public.
  • All secret or private keys will be referred to as secret.
  • The word key by itself does not indicate public or secret. The only exception is if the word key appears as part of a file suffix, where it is then considered the secret key file.
  • Origin - refers to build-time operations, including signing and verifification of an artifact.
  • Organization - refers to run-time operations that can happen in Habitat, such as deploying a package signed in a different origin into your own organization.
  • Signing keys - aka sig keys. These are used to sign and verify packages. Contains a sig.key file suffix. Sig keys are NOT compatible with box keys.
  • Box keys - used for encryption/decryption of arbitrary data. Contains a .box.key file suffix. Box keys are NOT compatible with sig keys.
  • Key revisions - Habitat can use several keys for any given user, service, or origin via different revision numbers. Revision numbers appear following the key name and are in the format
    {year}{month}{day}{hour24}{minute}{second}. For all user-facing cryptographic operations (sign/verify/encrypt/decrypt), the latest key is tried first, and upon failure, Habitat will try keys in reverse chronological order until success or there are no more keys. _TODO: key revisions are generated as part of a filename, but only the most recent key is used during crypto operations._

Example origin key file names ("sig" keys):

 habitat-201603312016.pub
 habitat-201603312016.sig.key
 your_company-201604021516.pub
 your_company-201604021516.sig.key

Example user keys ("box" keys)

Example Service keys:

Habitat signed artifact format

A signed .hab artifact has 3 plaintext lines followed by a binary blob of data, which is the unsigned tarfile.

  • The first plaintext line is the name of the origin signing key that was used to sign this artifact.
  • The second plaintext line is the hashing algorithm used, which will be BLAKE2b unless our use of crypto is expanded some time in the future.
  • The third plaintext line is a base64 signed value of the binary blob's base64 file hash. Signing uses a secret origin key, while verifying uses the public origin key. Thus, it it safe to distribute public origin keys.

Example header:

habitat-20160405144945
BLAKE2b
signed BLAKE2b signature
<binary-blob>

https://download.libsodium.org/doc/hashing/generic_hashing.html

It's possible to examine the contents of a .hab file from a Linux shell:

$ head -3 /opt/bldr/cache/pkgs/chef-glibc-2.22-20160310192356.bldr
habitat-20160405144945
BLAKE2b
w4yC7/QADdC+NfH/wgN5u4K94nMieb1TxTVzbSfpMwRQ4k+YwhLs1nDXSIbSC8jHdF/7/LqLWtgPvGDmoKIvBDI0aGpIcGdlNDJhMDBnQ3lsMVVFM0JvRlZGSHhXcnBuWWF0SllXTXo1ZDg9
# Note that this is an example signature only

It is also possible to extract a plain tarball from a signed .hab artifact using the following command:

tail -n +4 /tmp/somefile.hab > somefile.tar
# start at line 4, skipping the first 3 plaintext lines.

@bookshelfdave
Copy link
Contributor Author

I'll make the verify subcommand return an appropriate exit code instead of spitting out the tar file.

@bookshelfdave bookshelfdave force-pushed the dp_hab_nacl branch 2 times, most recently from 80a527a to df8f586 Compare April 8, 2016 13:51
iproute2 \
libsodium-dev \
sudo \
vim \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you alphabetize into the list? It should help with future merging

@fnichol
Copy link
Collaborator

fnichol commented Apr 8, 2016

@metadave I realize this might still be finishing up, but great work! You must have had fun with Rust/IO pushing all those files around.

Dave Parfitt added 4 commits April 8, 2016 13:15
Because we're using components/.cargo/config to override sodiumoxide
to point at a custom fork, we need to CD into each directory
instead of specifying the manifest location to allow the build to
complete.

- add iproute2 dep for `ip` command
$(run) cargo build --manifest-path components/hab/Cargo.toml
$(run) cargo build --manifest-path components/sup/Cargo.toml
$(run) cargo build --manifest-path components/depot/Cargo.toml
$(run) sh -c 'cd components/hab && cargo build'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this become a problem? Why change directory instead of just pass the manifest-path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, because of the components/.cargo/config file

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Cargo

gif-keyboard-16897976898869937003

@chef-delivery
Copy link
Contributor

This PR has passed 'Verify' and is ready for review and approval!
Use: '@delivery approve' when code review is complete.


/// If an env var is set, then return it's value.
/// If it's not, return the default
fn env_var_or_default(env_var: &str, default: &str) -> String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be better served in the util module instead of crypto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, I'll pull it out in my next few crypto PR's, as I have some more work do to w/ env vars etc.

@reset
Copy link
Collaborator

reset commented Apr 8, 2016

@metadave great work man, I'm looking forward to when they merge your changes ;). My comments are mostly just tips on how to be more fluent in Rust

@reset
Copy link
Collaborator

reset commented Apr 8, 2016

gif-keyboard-10185626448052687861

blast-off when ready

@bookshelfdave
Copy link
Contributor Author

thanks so much for the review @reset @fnichol
review fixes pushed, getting ready to merge soon

@bookshelfdave
Copy link
Contributor Author

Note, this needs to be merged after: #361

@chef-delivery
Copy link
Contributor

This PR has passed 'Verify' and is ready for review and approval!
Use: '@delivery approve' when code review is complete.

@bookshelfdave
Copy link
Contributor Author

@delivery approve

@chef-delivery chef-delivery merged commit d4eccfb into master Apr 8, 2016
@chef-delivery chef-delivery deleted the dp_hab_nacl branch April 8, 2016 21:30
@chef-delivery
Copy link
Contributor

Change: b7477faa-3da9-4c5d-b8a4-0697e52ae948 approved by: @metadave

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants