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

SAW verification of HMAC #305

Merged
merged 161 commits into from Sep 7, 2016

Conversation

Projects
None yet
5 participants
@jldodds
Contributor

jldodds commented Sep 6, 2016

This pull request contains the following:

  1. A Cryptol specification of HMAC.
  2. A SAW-script proving s2n_hmac.c equivalent to the cryptol specification at a variety of hash functions, message sizes, and key sizes.
  3. Further saw tests to ensure SAW catches bugs. We do this by patching a copy of the s2n code to introduce bugs and then running SAW on the patched code to ensure the bugs are detected. The current tests include an incorrect constant and malicious code that behaves incorrectly only when a certain byte has a specific value.
  4. Integration of all SAW tests into the s2n build system, runnable by make saw at the s2n root directory. Prerequisites are SAW, Clang, and Z3
  5. An updated .travis.yaml file that will run SAW for the linux tests on travis. For an example run see here

atomb and others added some commits Mar 28, 2016

Add rudimentary s2n Makefile
This will clone the s2n source and build LLVM bitcode files of the appropriate
pieces.
Add specification of SHA1
The includes the functional version of SHA1 that we had in the examples
directory of the Cryptol repository, as well as a more imperative
version (written in Cryptol) that consists of initialization, update,
and finalization functions. The SAWScript file proves that the
imperative version is equivalent to the functional version for various
specific message sizes.

It turns out that ABC is remarkably efficient at proving this! Probably
because the block function is completely identical on both sides of the
equality.

Note that I've included SHA1 simply as an example hash algorithm since
a clean specification of it was readily at hand. The same approach to
creating an imperative version should work equally well for any other
hash algorithm.
Add SHA256: both functional and imperative styles
The two styles are proved equivalent for various sizes using ABC, as in
the SHA1 spec.
Create self-contained bitcode file for HMAC
This contains everything needed for HMAC except the concrete hash
functions, which we're going to leave abstract anyway.
Add SAWScript file for SHA256 proofs
These proofs show equivalence between the functional and imperative
versions of SHA256 (both in Cryptol) for several specific message sizes.
Add skeleton HMAC spec
This includes a functional Cryptol spec of HMAC, as well as stubs for
the imperative version. It also includes stubs for the SAWScript
specifications of the C functions that abstract over specific hash
implementations in s2n.
Make `src/Makefile` work with a non OSX+Homebrew setup.
But it should still work with OSX+Homebrew, too, although I couldn't
test it.
First crack at imperative HMAC in Cryptol
This version type checks and runs but isn't quite correct yet. Nathan is
going to take over from here.
Add imperative HMAC vs functional HMAC test.
Turns out they are already equivalent:

    $ stack exec saw HMAC_imp_correct.saw
    Getting project config file from STACK_YAML environment
    Loading module Cryptol
    Loading file "HMAC_imp_correct.saw"
    Loading module SHA256
    Loading module HMAC
    Checking imp_correct for byte count 0
    Valid
    Time: 9.429029s
    Checking imp_correct for byte count 1
    Valid
    Time: 14.696618s
    Checking imp_correct for byte count 2
    Valid
    Time: 11.169244s
    Checking imp_correct for byte count 63
    Valid
    Time: 16.449585s
    Checking imp_correct for byte count 64
    Valid
    Time: 18.954719s
    Checking imp_correct for byte count 65
    Valid
    Time: 25.468452s
    Checking imp_correct for byte count 127
    Valid
    Time: 35.831754s
    Checking imp_correct for byte count 128
    Valid
    Time: 45.241426s
    Checking imp_correct for byte count 129
    Valid
    Time: 41.248373s
    Checking imp_correct for byte count 1000
    Valid
    Time: 257.975434s
    stack exec saw HMAC_imp_correct.saw  441.91s user 13.17s system 94% cpu 8:01.78 total
Add `tmp/TAGS` target to `src/Makefile`.
To generate Emacs tags for the s2n C sources.
Make imperative HMAC closer to s2n.
- Updated the `HMACState` to include all `s2n_hmac_state` fields except
  `alg`, which we've fixed to SHA256 for now.

- Modified the new fields in `hmac_init`, `hmac_update`, `hmac_reset`,
  and `hmac_digest`.

This Cryptol model still disagrees with s2n in a few places:

- the `outer` state coming out of `hmac_init` is not accurate: in s2n,
  it is used a scratch area for computing a hash on the key, when the
  key is too long. However, I think we want to avoid modeling this if
  possible, since this scratch value is never used again: `hmac_digest`
  calls `hash_reset` in `outer` before using it.

- the `outer` and `inner` state coming out of `hmac_digest` don't
  include update for the underlying hash's digest, since our Cryptol
  model of SHA256 has a digest ("Final") function which doesn't mutate
  the hash state. This may be because the hash digests are pure, but I
  have not verified this; the C interface allows them to change the hash
  state.
Add canonical s2n artifacts.
To be sure we're all verifying the same thing.
Axiomatize the `s2n_hash_init`.
Specialized to SHA256.

I made a layout/endianness assumption here that I have not checked: when
a smaller struct is embedded in the bits of a larger struct in a union,
I assumed the smaller struct will be in the initial higher order bits.
Specify `s2n_hash_update` and `s2n_hash_digest`.
And factor `setup_initial_hash_state` and `check_final_hash_state` out
of the `s2n_hash_init`, for reuse in the other specs. I wonder if this
abstraction would be possible if the state argument were not always
called `state`? I.e., could the arg name be a parameter?
Make hash-state setup and check functions more abstract.
The root of the "path" to the struct fields is now a parameter, so
that we can reuse the setup and check functions when setting up and
checking the hash states embedded in the hmac state.
Add C-struct wrappers for imperative HMAC Cryptol model.
I.e., translate between the C-struct as it appears in the LLVM, and
the Cryptol record we use in the imperative HMAC model. They're almost
the same, except that the nested hash states are treated differently
(they're much more complex in the C-struct).
Axiomitize HMAC specs.
These are still axioms, because running the proofs loops right
now. However, this is expected, and we'll need to treat some functions
as uninterpreted to make progress here.

Also, these specs are not complete: they don't enforce SHA256
everywhere yet.
Enable simulation for hmac_update and hmac_digest
These successfully run now, though I haven't tried to discharge the
resulting goals.

The hmac_init function still stalls. I expect it's for similar reasons
as the stalls that were affecting the update and digest functions, but
perhaps in a different instance.
Leave C hash state uninterpreted in `hmac_update_spec` and `hmac_dige…
…st_spec`.

This brings us closer to a hash-algorithm-agnostic spec, which is the
next goal. We don't abstract `hmac_init_spec` yet, because symbolic
simulation is still not working there.
Add hash-alg-agnostic hash type `hash_ty` and use it in `hmac_update_…
…spec`.

However, this approach isn't going to work for `hmac_digest_spec` yet,
since we need to call the hash update function at multiple msg sizes,
and it seems we can't have a higher rank (i.e. polymorphic `hash_ty`)
argument in Cryptol.
Start abstracting away from SHA256.
Not complete yet. We replaced the SHA256-specific hash calls with
calls to generic `hash_init_c_state`, `hash_update_c_state`, and
`hash_digest_c_state`, which we define as `undefined` and
uninterpret. This allows us to eliminate most SHA256 specific code
from the spec, but we now need to deal with constraining values in the
HMAC state enough to allow the simulation to complete without error.

We are not verifying the `s2n_hash_*` function specs against a real
hash implemention right now, but the idea is to write them in such a
way that they would be verifiable.
Distinguish `s2n_hash_update` calls as part of s2n build.
The `hmac.ll` and `hmac.bc` files came from C code that was patched to
distinguish `s2n_hash_update` calls in `s2n_hmac_digest`, but the
patch was not recorded anywhere. Now it is recorded, and applied
automatically as part of our `s2n` build process.
add saw to all target
move saw files into tests
put all bc files into the saw directory to avoid cluttering source dirs
make clean cleans bc files
better makefile orgainzation
support for patching if code needs changing (not expected to be needed in the long run)
fixed bitcode generation and linking
moved bitcode out of s2n source directory

jldodds and others added some commits Jul 21, 2016

break cryptol into files
 - Hashing, for hash interface and state
 - HMAC for top level specification
 - HMAC_iterative for the iterative/stateful interface to HMAC
 - HMAC_properties for the statement of properties relating the other files
Merge remote-tracking branch 'upstream/master'
Conflicts:
	.travis.yml
	tests/Makefile
better comment about init
fix travis typo

accidentally removed fuzzer install

fix python install
Add append proof for hmac_update
This proof shows that the imperative Cryptol version of hmac_update can
be called multiple times. That is, for any two messages, m1 and m2, the
result of calling update on m1 followed by update on m2 is equivalent to
calling update on m1 concatenated with m2.
Show outdated Hide outdated s2nbc.mk

@colmmacc colmmacc merged commit e09e5e1 into awslabs:master Sep 7, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment