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

Adds CBMC proof for sign_header #659

Merged
merged 24 commits into from
Jan 11, 2021
Merged

Adds CBMC proof for sign_header #659

merged 24 commits into from
Jan 11, 2021

Conversation

tegansb
Copy link
Contributor

@tegansb tegansb commented Dec 8, 2020

Adds harness, Makefile and yaml for sign_header.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Check any applicable:

  • Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.

@tegansb tegansb requested a review from alex-chew December 8, 2020 16:33
@tegansb tegansb added the cbmc CBMC proof related work label Dec 8, 2020
@tegansb tegansb requested a review from feliperodri December 8, 2020 16:33
Copy link
Contributor

@alex-chew alex-chew left a comment

Choose a reason for hiding this comment

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

Mostly LGTM, just a few nitpicks about naming/comments.

Comment on lines 171 to 176
AWS_PRECONDITION(session != NULL);
AWS_PRECONDITION(aws_allocator_is_valid(session->alloc));
AWS_PRECONDITION(aws_cryptosdk_hdr_is_valid(&session->header));
AWS_PRECONDITION(aws_cryptosdk_sig_ctx_is_valid(session->signctx));
AWS_PRECONDITION(session->state == ST_GEN_KEY);
AWS_PRECONDITION(session->mode == AWS_CRYPTOSDK_ENCRYPT);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Replace it by

AWS_PRECONDITION(aws_cryptosdk_session_is_valid(session));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated!

source/session_encrypt.c Outdated Show resolved Hide resolved
Comment on lines 171 to 178
AWS_PRECONDITION(session != NULL);
AWS_PRECONDITION(aws_allocator_is_valid(session->alloc));
AWS_PRECONDITION(aws_cryptosdk_hdr_is_valid(&session->header));
AWS_PRECONDITION(session->header.iv.len <= session->alg_props->iv_len);
AWS_PRECONDITION(session->header.auth_tag.len <= session->alg_props->tag_len);
AWS_PRECONDITION(aws_cryptosdk_sig_ctx_is_valid(session->signctx));
AWS_PRECONDITION(session->state == ST_GEN_KEY);
AWS_PRECONDITION(session->mode == AWS_CRYPTOSDK_ENCRYPT);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't need an unique allocator for session to cope with proof complexity, but we should have a validity function for it. Could you group the general checks here into a validity function for aws_cryptosdk_session structures?

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! This has been updated!

Comment on lines 194 to 201
if (session->header.iv.len) {
assert(session->header.iv.buffer);
memset(session->header.iv.buffer, 0x42, session->header.iv.len);
}
if (session->header.auth_tag.len) {
assert(session->header.auth_tag.buffer);
memset(session->header.auth_tag.buffer, 0xDE, session->header.auth_tag.len);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we assert or return error? @alex-chew

Copy link
Contributor

Choose a reason for hiding this comment

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

Short answer: assert. The condition should always be true, and if not then it's a programming error rather than a user/data error.

Long answer: I think we can actually leave out the assert, since the aws_cryptosdk_hdr_is_valid(&session->header) precondition implies that the session->header.iv and session->header.auth_tag are aws_byte_buf_is_valid, which in turn implies that iv.len implies iv.buffer and likewise for auth_tag. But the assert is valuable as documentation of this intent.

Copy link
Contributor

Choose a reason for hiding this comment

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

Digging deeper, it looks like the only callsite of sign_header appears after a successfull call to build_header, which initializes these buffers to have positive length (since all supported algorithm suites use 12- and 16-byte IVs and authentication tag lengths, respectively). So we can change the guards/asserts to preconditions (i.e. byte_buf_is_valid and buf.len > 0 for each of the IV and auth tag).

source/session_encrypt.c Outdated Show resolved Hide resolved
verification/cbmc/proofs/sign_header/Makefile Outdated Show resolved Hide resolved
AWS_PRECONDITION(session->header.iv.len <= session->alg_props->iv_len);
AWS_PRECONDITION(session->header.auth_tag.len <= session->alg_props->tag_len);
AWS_PRECONDITION(aws_cryptosdk_sig_ctx_is_valid(session->signctx));
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker, but I'm curious why this is no longer needed?

Copy link
Collaborator

@adpaco-aws adpaco-aws Jan 6, 2021

Choose a reason for hiding this comment

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

Thanks for bringing this up. I will check if the associated assumption in the harness can be removed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@alex-chew we have investigated this issue and we have decided to remove the assumption from the harness. Note that the session validator allows session->signctx to be either NULL or valid. To do so, we modified a precondition in EVP_DigestUpdate which we think is too restrictive.

Moreover, we have opened an issue (#685) to remove this type of validators from the code base, since they cannot be mirrored as preconditions.

Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

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

LGTM.

@adpaco-aws
Copy link
Collaborator

The last changes include a stub for aws_cryptosdk_hdr_write which causes the proof to run much faster than earlier.

@feliperodri can you take a look at this stub and let us know what you think? The original function can be found here:

int aws_cryptosdk_hdr_write(
const struct aws_cryptosdk_hdr *hdr, size_t *bytes_written, uint8_t *outbuf, size_t outlen) {
AWS_PRECONDITION(aws_cryptosdk_hdr_is_valid(hdr));
AWS_PRECONDITION(hdr->iv.len <= UINT8_MAX); // uint8_t max value
AWS_PRECONDITION(outlen == 0 || AWS_MEM_IS_READABLE(outbuf, outlen));
AWS_PRECONDITION(bytes_written != NULL);
struct aws_byte_buf output = aws_byte_buf_from_array(outbuf, outlen);
output.len = 0;
const struct aws_cryptosdk_alg_properties *alg_props = aws_cryptosdk_alg_props(hdr->alg_id);
if (!alg_props) goto INVALID_HEADER;
enum aws_cryptosdk_hdr_version header_version = alg_props->msg_format_version;
if (!aws_byte_buf_write_u8(&output, header_version)) goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write_u8(&output, AWS_CRYPTOSDK_HEADER_TYPE_CUSTOMER_AED)) goto WRITE_ERR;
}
if (!aws_byte_buf_write_be16(&output, hdr->alg_id)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->message_id.buffer, hdr->message_id.len)))
goto WRITE_ERR;
// TODO - unify everything on byte_bufs when the aws-c-common refactor lands
// See: https://github.com/awslabs/aws-c-common/pull/130
struct aws_byte_buf aad_length_field;
init_aws_byte_buf_raw(&aad_length_field);
if (!aws_byte_buf_advance(&output, &aad_length_field, 2)) goto WRITE_ERR;
size_t old_len = output.len;
if (aws_cryptosdk_enc_ctx_serialize(aws_default_allocator(), &output, &hdr->enc_ctx)) goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&aad_length_field, (uint16_t)(output.len - old_len))) goto WRITE_ERR;
size_t edk_count = aws_array_list_length(&hdr->edk_list);
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk_count)) goto WRITE_ERR;
for (size_t idx = 0; idx < edk_count; ++idx) {
void *vp_edk = NULL;
aws_array_list_get_at_ptr(&hdr->edk_list, &vp_edk, idx);
assert(vp_edk);
const struct aws_cryptosdk_edk *edk = vp_edk;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_id.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->provider_id.buffer, edk->provider_id.len)))
goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->provider_info.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->provider_info.buffer, edk->provider_info.len)))
goto WRITE_ERR;
if (!aws_byte_buf_write_be16(&output, (uint16_t)edk->ciphertext.len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(edk->ciphertext.buffer, edk->ciphertext.len)))
goto WRITE_ERR;
}
if (!aws_byte_buf_write_u8(
&output, hdr->frame_len ? AWS_CRYPTOSDK_HEADER_CTYPE_FRAMED : AWS_CRYPTOSDK_HEADER_CTYPE_NONFRAMED))
goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write(&output, zero.bytes, 4)) goto WRITE_ERR; // v01 reserved field
if (!aws_byte_buf_write_u8(&output, (uint8_t)hdr->iv.len)) goto WRITE_ERR;
}
if (!aws_byte_buf_write_be32(&output, hdr->frame_len)) goto WRITE_ERR;
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->alg_suite_data.buffer, hdr->alg_suite_data.len)))
goto WRITE_ERR;
if (header_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
if (!aws_byte_buf_write_from_whole_cursor(&output, aws_byte_cursor_from_array(hdr->iv.buffer, hdr->iv.len)))
goto WRITE_ERR;
}
if (!aws_byte_buf_write_from_whole_cursor(
&output, aws_byte_cursor_from_array(hdr->auth_tag.buffer, hdr->auth_tag.len)))
goto WRITE_ERR;
*bytes_written = output.len;
return AWS_OP_SUCCESS;
INVALID_HEADER:
aws_secure_zero(outbuf, outlen);
*bytes_written = 0;
return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE);
WRITE_ERR:
aws_secure_zero(outbuf, outlen);
*bytes_written = 0;
return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
}

@adpaco-aws adpaco-aws marked this pull request as ready for review January 11, 2021 12:16
Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

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

LGTM, modulo a few suggestions.

Comment on lines +67 to +68
PROOF_SOURCES += $(COMMON_PROOF_STUB)/aws_byte_buf_write_stub.c
PROOF_SOURCES += $(COMMON_PROOF_STUB)/aws_hash_iter_overrides.c
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 create a GitHub issue to standardize the name of stubs? Some of them use as sufix stub some others use overrides some other use something else... (no a blocker for this PR).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Done! #686

verification/cbmc/proofs/sign_header/Makefile Show resolved Hide resolved
verification/cbmc/proofs/sign_header/Makefile Outdated Show resolved Hide resolved
Comment on lines 20 to 27
/*
* Stub for aws_cryptosdk_hdr_write
* The original function declares an aws_byte_buf output variable where
* different components of the header get written, but the actual output
* of the function is bytes_written. Therefore, we assign a nondet. value
* to this variable in case of success or zero both outbuf and outlen in
* case of failure
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Suggestion:

/**
 * The original aws_cryptosdk_hdr_write function declares an aws_byte_buf
 * output variable where different components of the header get written,
 * however, the actual output of the function is bytes_written. Therefore,
 * we assign a nondeterministic value to bytes_written in case of success
 * or zero both outbuf and outlen in case of failure.
 */

Copy link
Collaborator

Choose a reason for hiding this comment

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

The stub looks great. How much gain in performance?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks! It was ~40min on my dedicated machine before, but only ~10min now 😄

@adpaco-aws adpaco-aws merged commit f2e9593 into aws:master Jan 11, 2021
alex-chew added a commit that referenced this pull request Jan 15, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves #639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
robin-aws pushed a commit to robin-aws/aws-encryption-sdk-c that referenced this pull request Apr 26, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves aws#639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
robin-aws pushed a commit to robin-aws/aws-encryption-sdk-c that referenced this pull request Apr 29, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves aws#639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
robin-aws pushed a commit to robin-aws/aws-encryption-sdk-c that referenced this pull request May 4, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves aws#639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
robin-aws pushed a commit to robin-aws/aws-encryption-sdk-c that referenced this pull request May 4, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves aws#639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
robin-aws pushed a commit that referenced this pull request May 5, 2021
* Split aws_cryptosdk_hdr_parse into smaller functions

Resolves #639.

* Adds harness, Makefile and yaml for sign_header

* Added preconditions to source code and added checks for memcpy

* Update Makefile

* Remove unneeded empty slot assumption

* Use new hdr_setup in harness and fix comment

* Added comment about when the object-bits flag is required

* Added preconditions of lne of byte bufs

* Use CBMC_OBJECT_BITS flag

* Make len != 0 check explicit

* Use session_setup and aws_session_is_valid

* Remove signctx precondition in harness. Weaken precondition in EVPDigestUpdate

* Stub out hdr_write. Use default CBMC_OBJECT_BITS value

* Remove unwind value for hdr_write

* Add and improve documentation

Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Alex Chew <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Co-authored-by: Adrian Palacios <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cbmc CBMC proof related work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants