Skip to content

Commit

Permalink
Update SHA proof for "moving AArch64/X86_64 dispatching to C" changes (
Browse files Browse the repository at this point in the history
…#155)

* Update SHA proof for moving AArch64/X86_64 dispatching to C changes

* Using lax_pointer_ordering to fix pointer comparison optimization

* Add the LaxPointer caveat

* Update src
  • Loading branch information
pennyannn authored Jul 29, 2024
1 parent 225865c commit c8c1569
Show file tree
Hide file tree
Showing 19 changed files with 170 additions and 35 deletions.
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[submodule "src"]
path = src
branch = main
url = https://github.com/aws/aws-lc.git
branch = upstream-sha-asm
url = https://github.com/justsmth/aws-lc.git
[submodule "cryptol-specs"]
path = cryptol-specs
branch = sha-imperative
Expand Down
4 changes: 2 additions & 2 deletions NSym/proof/proofs/SHA512/sha512_program.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ let print_hex (intstr : string) : unit =
Format.fprintf Format.std_formatter "@[<1>%s@]@." hexstr;;

let (sha512_block_armv8_start_address, sha512_block_armv8_dump) =
Elf.symbol_contents ~section_name:".symtab" "sha512_block_armv8" elf;;
Elf.symbol_contents ~section_name:".symtab" "sha512_block_data_order_hw" elf;;
let sha512_block_armv8_bytes =
(Elf.uint32_list_of_data sha512_block_armv8_dump);;

(* Print, in hex, the list of sha512_block_armv8 instructions. *)
let _ = List.iter (fun i -> print_hex (Int.to_string i)) sha512_block_armv8_bytes;;

let (sha512_block_data_order_start_address, sha512_block_data_order_dump) =
Elf.symbol_contents ~section_name:".symtab" "sha512_block_data_order" elf;;
Elf.symbol_contents ~section_name:".symtab" "sha512_block_data_order_nohw" elf;;
let sha512_block_data_order_bytes =
(Elf.uint32_list_of_data sha512_block_data_order_dump);;

Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ AWS libcrypto includes many cryptographic algorithm implementations for several
| Algorithm | Variants | API Operations | Platform | Caveats | Tech |
| ----------| -------------| --------------- | -----------| ------------ | --------- |
| [SHA-2](SPEC.md#SHA-2) | 384, 512 | EVP_DigestInit, EVP_DigestUpdate, EVP_DigestFinal | SandyBridge+ | NoEngine, MemCorrect | SAW |
| [SHA-2](SPEC.md#SHA-2) | 384 | EVP_DigestInit, EVP_DigestUpdate, EVP_DigestFinal | neoverse-n1, neoverse-v1 | NoEngine, MemCorrect, ArmSpecGap, ToolGap | SAW, NSym |
| [SHA-2](SPEC.md#SHA-2) | 384, 512 | EVP_DigestInit, EVP_DigestUpdate, EVP_DigestFinal | neoverse-n1, neoverse-v1 | NoEngine, NoInline, MemCorrect, ArmSpecGap, ToolGap, LaxPointer | SAW, NSym |
| [HMAC](SPEC.md#HMAC-with-SHA-384) | with <nobr>SHA-384</nobr> | HMAC_CTX_init, HMAC_Init_ex, HMAC_Update, HMAC_Final, HMAC | SandyBridge+ | NoEngine, MemCorrect, InitZero, NoInline, CRYPTO_once_Correct | SAW |
| [<nobr>AES-KW(P)</nobr>](SPEC.md#AES-KWP) | 256 | AES_wrap_key, AES_unwrap_key, AES_wrap_key_padded, AES_unwrap_key_padded | SandyBridge+ | InputLength, MemCorrect, NoInline | SAW |
| [<nobr>AES-GCM</nobr>](SPEC.md#AES-GCM) | 256 | EVP_CipherInit_ex, EVP_CIPHER_CTX_ctrl, EVP_EncryptUpdate, EVP_DecryptUpdate, EVP_EncryptFinal_ex, EVP_DecryptFinal_ex | SandyBridge-Skylake | MemCorrect, NoInline, GcmSpecGap, GcmMultipleOf16, GcmADNotVerified, GcmIV12Tag16, GcmWellFoundedInduction | SAW |
<!--- | [Elliptic Curve Keys and Parameters](SPEC.md#Elliptic-Curve-Keys-and-Parameters) | with <nobr>P-384</nobr> | EVP_PKEY_CTX_new_id, EVP_PKEY_CTX_new, EVP_PKEY_paramgen_init, EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_paramgen, EVP_PKEY_keygen_init, EVP_PKEY_keygen | SandyBridge+ | SAWCore_Coq, EC_Fiat_Crypto, ToolGap, NoEngine, MemCorrect, CRYPTO_refcount_Correct, CRYPTO_once_Correct, OptNone, SAWBreakpoint | SAW, Coq |
| [ECDSA](SPEC.md#ECDSA) | with <nobr>P-384</nobr>, <nobr>SHA-384</nobr> | EVP_DigestSignInit, EVP_DigestVerifyInit, EVP_DigestSignUpdate, EVP_DigestVerifyUpdate, EVP_DigestSignFinal, EVP_DigestVerifyFinal, EVP_DigestSign, EVP_DigestVerify | SandyBridge+ | EC_Pub_Mul_Correct, EC_Constants_Correct, EC_Conversion_Correct, SAWCore_Coq, EC_Fiat_Crypto, NoEngine, MemCorrect, ECDSA_k_Valid, ECDSA_SignatureLength, CRYPTO_refcount_Correct, CRYPTO_once_Correct, ERR_put_error_Correct, NoInline | SAW, Coq |
| [ECDH](SPEC.md#ECDH) | with <nobr>P-384</nobr> | EVP_PKEY_derive_init, EVP_PKEY_derive | SandyBridge+ | SAWCore_Coq, EC_Fiat_Crypto, ECDH_InfinityTestCorrect, ToolGap, MemCorrect, NoEngine, CRYPTO_refcount_Correct, PubKeyValid | SAW, Coq | --->
| [HKDF](SPEC.md#HKDF-with-HMAC-SHA384) | with <nobr>HMAC-SHA384</nobr> | HKDF_extract, HKDF_expand, HKDF | SandyBridge+ | MemCorrect, NoEngine, NoInline, OutputLength, CRYPTO_once_Correct | SAW |
<!--- | [Elliptic Curve Keys and Parameters](SPEC.md#Elliptic-Curve-Keys-and-Parameters) | with <nobr>P-384</nobr> | EVP_PKEY_CTX_new_id, EVP_PKEY_CTX_new, EVP_PKEY_paramgen_init, EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_paramgen, EVP_PKEY_keygen_init, EVP_PKEY_keygen | SandyBridge+ | SAWCore_Coq, EC_Fiat_Crypto, ToolGap, NoEngine, MemCorrect, CRYPTO_refcount_Correct, CRYPTO_once_Correct, OptNone, SAWBreakpoint, LaxPointer | SAW, Coq | --->
<!--- | [ECDSA](SPEC.md#ECDSA) | with <nobr>P-384</nobr>, <nobr>SHA-384</nobr> | EVP_DigestSignInit, EVP_DigestVerifyInit, EVP_DigestSignUpdate, EVP_DigestVerifyUpdate, EVP_DigestSignFinal, EVP_DigestVerifyFinal, EVP_DigestSign, EVP_DigestVerify | SandyBridge+ | EC_Pub_Mul_Correct, EC_Constants_Correct, EC_Conversion_Correct, SAWCore_Coq, EC_Fiat_Crypto, NoEngine, MemCorrect, ECDSA_k_Valid, ECDSA_SignatureLength, CRYPTO_refcount_Correct, CRYPTO_once_Correct, ERR_put_error_Correct, NoInline | SAW, Coq | --->
<!--- | [ECDH](SPEC.md#ECDH) | with <nobr>P-384</nobr> | EVP_PKEY_derive_init, EVP_PKEY_derive | SandyBridge+ | SAWCore_Coq, EC_Fiat_Crypto, ECDH_InfinityTestCorrect, ToolGap, MemCorrect, NoEngine, CRYPTO_refcount_Correct, PubKeyValid | SAW, Coq | --->

The platforms for which code is verified are defined in the following table. In all cases, the actual verification is performed on code that is produced by Clang, but the verification results also apply to any compiler that produces semantically equivalent code.

Expand Down Expand Up @@ -86,6 +86,7 @@ The caveats associated with some of the verification results are defined in the
| GcmADNotVerified | Supplying additional data (AD) to AES-GCM is not verified. |
| GcmIV12Tag16 | The AES-GCM functions are only verified for 12-byte IVs and 16-byte tags. |
| GcmWellFoundedInduction | The AES-GCM proofs make use of inductive proofs to prove theorems about unbounded loops, but the inductive hypotheses are assumed, as SAW lacks a well-foundedness check for the inductive invariants. |
| LaxPointer | The Clang optimization will sometimes introduce comparisons between pointers from different allocation blocks. This is considered an undefined behaviour in SAW. In these benign cases, we use `enable_lax_pointer_ordering` to disable such pointer checks.


### Functions with compiler optimization disabled
Expand Down
14 changes: 14 additions & 0 deletions SAW/patch/noinline-CRYPTO_bswap8.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
diff --git a/crypto/internal.h b/crypto/internal.h
index 767a6a925..1a6b51b67 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -770,7 +770,8 @@ static inline uint32_t CRYPTO_bswap4(uint32_t x) {
return __builtin_bswap32(x);
}

-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+__attribute__((noinline))
+static uint64_t CRYPTO_bswap8(uint64_t x) {
return __builtin_bswap64(x);
}
static inline crypto_word_t CRYPTO_bswap_word(crypto_word_t x) {
85 changes: 85 additions & 0 deletions SAW/proof/SHA512/SHA512-aarch64.saw
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
// Include SHA512 helper functions
include "SHA512-common.saw";

// Include internal function overrides
include "../common/internal_aarch64.saw";

// Include rewrite rules
include "goal-rewrites.saw";

// Verify the `EVP_SHA_INIT` C function satisfies the `EVP_sha_init_spec`
// specification
llvm_verify m EVP_SHA_INIT [] true EVP_sha_init_spec (w4_unint_yices []);


// Verify the `EVP_DigestInit` C function satisfies the
// `EVP_DigestInit_array_spec` unbounded specification.
llvm_verify m "EVP_DigestInit"
[ OPENSSL_malloc_init_ov
, OPENSSL_free_null_ov
]
true
EVP_DigestInit_array_spec
(do {
goal_eval_unint [];
w4_unint_z3 [];
});

// Verify the `EVP_DigestUpdate` C function satisfies the
// `EVP_DigestUpdate_array_spec` unbounded specification.
EVP_DigestUpdate_array_ov <- llvm_verify m "EVP_DigestUpdate"
[sha512_block_data_order_array_ov]
true
EVP_DigestUpdate_array_spec
(do {
goal_eval_unint ["processBlocks", "processBlock_Common"];
simplify (addsimps [processBlocks_0_1_thm] empty_ss);
simplify (addsimps [arrayRangeEq_arrayRangeLookup_eq_thm, arrayCopy_zero_thm] empty_ss);
simplify (addsimps append_ite_thms empty_ss);
goal_eval_unint ["processBlocks", "processBlock_Common"];
w4_unint_z3 ["processBlocks", "processBlock_Common"];
});


// Verify the `EVP_DigestFinal` C function satisfies the
// `EVP_DigestFinal_array_spec` unbounded specification.
// Note:
// When results in sha->h[i] are copied into out,
// LLVM does an optimization using vectorized bswap. This vectorized
// bswap requires that memory region of sha->h and out are non-overlapping.
// To ensure the non-overlapping condition, in LLVM IR, it does two comparisons:
// overlapping = end(sha->h) > begin(out) && end(out) > begin(sha->h)
// This comparison compares pointers from different locations,
// triggers an undefined behaviour and therefore SAW errors.
// Enabling lax_pointer_ordering to allow this behaviour.
// For more information see https://github.com/GaloisInc/saw-script/issues/1308
enable_lax_pointer_ordering;

let verify_final_with_length withLength = do {
print (str_concat "Verifying EVP_DigestFinal withLength=" (show withLength));
enable_what4_eval;
llvm_verify m "EVP_DigestFinal"
[ sha512_block_data_order_array_ov
, OPENSSL_free_nonnull_ov
, OPENSSL_cleanse_ov
, CRYPTO_bswap8_ov
]
true
(EVP_DigestFinal_array_spec withLength)
(do {
goal_eval_unint ["processBlock_Common"];
simplify (addsimps [arrayUpdate_arrayCopy_thm, arraySet_zero_thm] empty_ss);
simplify (addsimps [bvult_64_32_thm] empty_ss);
simplify (addsimps append_ite_thms empty_ss);
goal_eval_unint ["processBlock_Common"];
w4_unint_z3 ["processBlock_Common"];
});
disable_what4_eval;
};
for [false, true] verify_final_with_length;

disable_lax_pointer_ordering;
10 changes: 8 additions & 2 deletions SAW/proof/SHA512/SHA512-common.saw
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ EVP_MD_pctx_ops_ov <- llvm_unsafe_assume_spec

enable_what4_hash_consing;

sha512_block_data_order_ov <- llvm_verify_or_assume_asm m "../../build/x86/crypto/crypto_test" "sha512_block_data_order"
let func = if eval_bool {{ARCH@@[0..2] == "X86"}}
then "sha512_block_data_order_avx"
else if eval_bool {{MicroARCH == "neoverse_n1"}}
then "sha512_block_data_order_nohw"
else "sha512_block_data_order_hw";

sha512_block_data_order_ov <- llvm_verify_or_assume_asm m "../../build/x86/crypto/crypto_test" func
[ ("K512", 5120) // Initializes the global for round constants, called K, at a size of 5120 bytes
]
true
Expand All @@ -52,7 +58,7 @@ sha512_block_data_order_ov <- llvm_verify_or_assume_asm m "../../build/x86/crypt
enable_what4_eval;
enable_x86_what4_hash_consing;

sha512_block_data_order_array_ov <- llvm_verify_or_assume_fixpoint_asm m "../../build/x86/crypto/crypto_test" "sha512_block_data_order"
sha512_block_data_order_array_ov <- llvm_verify_or_assume_fixpoint_asm m "../../build/x86/crypto/crypto_test" func
[ ("K512", 5120) // Initializes the global for round constants, called K, at a size of 5120 bytes
]
true
Expand Down
9 changes: 0 additions & 9 deletions SAW/proof/SHA512/SHA512.saw
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,6 @@ EVP_DigestUpdate_array_ov <- llvm_verify m "EVP_DigestUpdate"

// Verify the `EVP_DigestFinal` C function satisfies the
// `EVP_DigestFinal_array_spec` unbounded specification.
// TODO:
// Currently this proof fails due to an undefined behaviour.
// Specifically, when results in sha->h[i] are copied into out,
// LLVM does an optimization using vectorized bswap. This vectorized
// bswap requires that memory region of sha->h and out are non-overlapping.
// To ensure the non-overlapping condition, in LLVM IR, it does two comparisons:
// overlapping = end(sha->h) > begin(out) && end(out) > begin(sha->h)
// This comparison compares pointers from different locations,
// triggers an undefined behaviour and therefore SAW errors.
let verify_final_with_length withLength = do {
print (str_concat "Verifying EVP_DigestFinal withLength=" (show withLength));
enable_what4_eval;
Expand Down
3 changes: 2 additions & 1 deletion SAW/proof/SHA512/aarch64-neoverse-n1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
// Name of the OPENSSL machine cap variable
let cap_sym = "OPENSSL_armcap_P";
// Set machine cap value
// The value is acquired by printing OPENSSL_armcap_P in AWS-LC on Graviton3
// The value is acquired by printing OPENSSL_armcap_P in AWS-LC on Graviton2
let {{ machine_cap = 0x0000003D : [32] }};
// Set the architecture variable for controlling proof settings
let ARCH = "AARCH64";
let MicroARCH = "neoverse_n1";
1 change: 1 addition & 0 deletions SAW/proof/SHA512/aarch64-neoverse-v1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ let cap_sym = "OPENSSL_armcap_P";
let {{ machine_cap = 0x0000187D : [32] }};
// Set the architecture variable for controlling proof settings
let ARCH = "AARCH64";
let MicroARCH = "neoverse_v1";
2 changes: 1 addition & 1 deletion SAW/proof/SHA512/verify-SHA384-aarch64-neoverse-n1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import "../../../cryptol-specs/Primitive/Keyless/Hash/SHA384.cry";

include "SHA384-defines.saw";
include "aarch64-neoverse-n1.saw";
include "SHA512.saw";
include "SHA512-aarch64.saw";
2 changes: 1 addition & 1 deletion SAW/proof/SHA512/verify-SHA384-aarch64-neoverse-v1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import "../../../cryptol-specs/Primitive/Keyless/Hash/SHA384.cry";

include "SHA384-defines.saw";
include "aarch64-neoverse-v1.saw";
include "SHA512.saw";
include "SHA512-aarch64.saw";
2 changes: 1 addition & 1 deletion SAW/proof/SHA512/verify-SHA512-aarch64-neoverse-n1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import "../../../cryptol-specs/Primitive/Keyless/Hash/SHA512.cry";

include "SHA512-defines.saw";
include "aarch64-neoverse-n1.saw";
include "SHA512.saw";
include "SHA512-aarch64.saw";
2 changes: 1 addition & 1 deletion SAW/proof/SHA512/verify-SHA512-aarch64-neoverse-v1.saw
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import "../../../cryptol-specs/Primitive/Keyless/Hash/SHA512.cry";

include "SHA512-defines.saw";
include "aarch64-neoverse-v1.saw";
include "SHA512.saw";
include "SHA512-aarch64.saw";
10 changes: 8 additions & 2 deletions SAW/proof/common/asm_helpers.saw
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

enable_experimental;

include "../common/helpers.saw";

// ARCH is either "X86_64":[6] or "AARCH64":[7], note they are of different types
// We will get a type error if we directly compare ARCH with "X86_64"
// when ARCH is set to be "AARCH64".
Expand All @@ -16,10 +18,14 @@ let load_module = if asm_switch

let llvm_verify_or_assume_asm m bin func globals pathsat spec tactic =
if asm_switch
then llvm_verify_x86 m bin func globals pathsat spec tactic
then if do_prove
then llvm_verify_x86 m bin func globals pathsat spec tactic
else crucible_llvm_unsafe_assume_spec m func spec
else crucible_llvm_unsafe_assume_spec m func spec;

let llvm_verify_or_assume_fixpoint_asm m bin func globals pathsat loop spec tactic =
if asm_switch
then llvm_verify_fixpoint_x86 m bin func globals pathsat loop spec tactic
then if do_prove
then llvm_verify_fixpoint_x86 m bin func globals pathsat loop spec tactic
else crucible_llvm_unsafe_assume_spec m func spec
else crucible_llvm_unsafe_assume_spec m func spec;
9 changes: 4 additions & 5 deletions SAW/proof/common/internal.saw
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ let CRYPTO_get_fork_generation_spec = do {
crucible_return (crucible_term ret);
};

CRYPTO_get_fork_generation_ov <- crucible_llvm_unsafe_assume_spec
m
"CRYPTO_get_fork_generation"
(CRYPTO_get_fork_generation_spec);


// Proof commands

Expand Down Expand Up @@ -133,3 +128,7 @@ CRYPTO_MUTEX_unlock_write_ov <- crucible_llvm_unsafe_assume_spec
"CRYPTO_MUTEX_unlock_write"
CRYPTO_MUTEX_lock_spec;

CRYPTO_get_fork_generation_ov <- crucible_llvm_unsafe_assume_spec
m
"CRYPTO_get_fork_generation"
(CRYPTO_get_fork_generation_spec);
22 changes: 22 additions & 0 deletions SAW/proof/common/internal_aarch64.saw
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

// Specs and proofs related to functions in internal.h (constant time code, reference counting, locks, etc.)

let {{
bswap8 : [64] -> [64]
bswap8 x = join (reverse (split`{each=8} x))
}};

let CRYPTO_bswap8_spec = do {
x <- crucible_fresh_var "x" (llvm_int 64);
crucible_execute_func [ (crucible_term x) ];
crucible_return (crucible_term {{ bswap8 x }});
};

CRYPTO_bswap8_ov <- crucible_llvm_unsafe_assume_spec
m
"CRYPTO_bswap8"
CRYPTO_bswap8_spec;
10 changes: 10 additions & 0 deletions SAW/scripts/aarch64/entrypoint_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
set -ex

PATH=/lc/bin:/go/bin:$PATH
PATCH=$(realpath ./patch)

apply_patch() {
PATCH_NAME=$1

(cd ../src; patch -p1 -r - --forward < "$PATCH"/"$PATCH_NAME".patch || true)
}

go env -w GOPROXY=direct

# Apply the patches
apply_patch "noinline-CRYPTO_bswap8"

# The following warning seems like a bug in wllvm and are benign
# WARNING:Did not recognize the compiler flag "--target=aarch64-unknown-linux-gnu"
./scripts/aarch64/build_llvm.sh "Release"
Expand Down
5 changes: 2 additions & 3 deletions SAW/scripts/aarch64/release_jobs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@

saw proof/SHA512/verify-SHA384-aarch64-neoverse-n1.saw
saw proof/SHA512/verify-SHA384-aarch64-neoverse-v1.saw
# TODO: Currently SHA512 proofs are disabled due to a safety check failure
# saw proof/SHA512/verify-SHA512-aarch64-neoverse-n1.saw
# saw proof/SHA512/verify-SHA512-aarch64-neoverse-v1.saw
saw proof/SHA512/verify-SHA512-aarch64-neoverse-n1.saw
saw proof/SHA512/verify-SHA512-aarch64-neoverse-v1.saw
2 changes: 1 addition & 1 deletion src
Submodule src updated 136 files

0 comments on commit c8c1569

Please sign in to comment.